6060#include < rapidjson/rapidjson.h>
6161#include " cover/coVRConfig.h"
6262#include < PluginUtil/PluginMessageTypes.h>
63- #include < ../../../../3rdparty/easyexif/exif.h>
6463#include < stdio.h>
6564
6665using namespace vrui ;
6766using namespace opencover ;
68-
67+ # include < exiv2/exiv2.hpp >
6968namespace opencover
7069{
7170namespace ui
@@ -531,8 +530,7 @@ bool GeoDataLoader::init()
531530 std::cerr << " GeoData Error: Invalid input" << std::endl;
532531 }
533532
534- saveOffsetToConfig->setState (false );
535- });
533+ saveOffsetToConfig->setState (false ); });
536534
537535 visibilityGroup = new ui::Group (geoDataMenu, " visibility" );
538536 visibilityGroup->setText (" Toggle Visibility" );
@@ -682,18 +680,90 @@ bool GeoDataLoader::init()
682680 fclose (fp);
683681
684682 // Parse EXIF
685- easyexif::EXIFInfo result;
686- int code = result.parseFrom (buf, bsize);
687- double skyLon = result.GeoLocation .Longitude ;
688- double skyLat = result.GeoLocation .Latitude ;
689- se.skyLongitude = skyLon;
690- se.skyLatitude = skyLat;
691- se.skyTrueNorth = 0.0 ; // TODO: read true north from config if available
692- delete[] buf;
693- if (code)
683+ float gimbalYaw = 0 .0f ;
684+ float flightYaw = 0 .0f ;
685+
686+ auto image = Exiv2::ImageFactory::open (entry.path ().string ());
687+ image->readMetadata ();
688+ auto &exif = image->exifData ();
689+ if (exif.empty ())
690+ {
691+ std::cerr << " No EXIF data found in " << entry.path ().string () << std::endl;
692+ se.skyLongitude = 0.0 ;
693+ se.skyLatitude = 0.0 ;
694+ }
695+ else
696+ {
697+ auto latIt = exif.findKey (Exiv2::ExifKey (" Exif.GPSInfo.GPSLatitude" ));
698+ if (latIt == exif.end ())
699+ {
700+ std::cerr << " No GPS Latitude found in EXIF data of " << entry.path ().string () << std::endl;
701+ se.skyLatitude = 0.0 ;
702+ }
703+ else
704+ {
705+ Exiv2::URational latDeg = exif[" Exif.GPSInfo.GPSLatitude" ].toRational (0 );
706+ Exiv2::URational latMin = exif[" Exif.GPSInfo.GPSLatitude" ].toRational (1 );
707+ Exiv2::URational latSec = exif[" Exif.GPSInfo.GPSLatitude" ].toRational (2 );
708+ se.skyLatitude = latDeg.first + latMin.first / (60.0 * latMin.second ) + latSec.first / (3600.0 * latSec.second );
709+ }
710+ auto lonIt = exif.findKey (Exiv2::ExifKey (" Exif.GPSInfo.GPSLongitude" ));
711+ if (lonIt == exif.end ())
712+ {
713+ std::cerr << " No GPS Longitude found in EXIF data of " << entry.path ().string () << std::endl;
714+ se.skyLongitude = 0.0 ;
715+ }
716+ else
717+ {
718+ Exiv2::URational lonDeg = exif[" Exif.GPSInfo.GPSLongitude" ].toRational (0 );
719+ Exiv2::URational lonMin = exif[" Exif.GPSInfo.GPSLongitude" ].toRational (1 );
720+ Exiv2::URational lonSec = exif[" Exif.GPSInfo.GPSLongitude" ].toRational (2 );
721+ se.skyLongitude = lonDeg.first + lonMin.first / (60.0 * lonMin.second ) + lonSec.first / (3600.0 * lonSec.second );
722+ }
723+
724+ }
725+
726+ Exiv2::XmpData &xmpData = image->xmpData ();
727+ if (xmpData.empty ())
694728 {
695- printf (" Error parsing EXIF: code %d\n " , code);
729+ std::cerr << " No XMP data found in " << entry.path ().string () << std::endl;
730+ se.skyTrueNorth = 0.0 ;
731+ }
732+ else
733+ {
734+ auto gimbalYawIt = xmpData.findKey (Exiv2::XmpKey (" Xmp.drone-dji.GimbalYawDegree" ));
735+ if (gimbalYawIt == xmpData.end ())
736+ {
737+ std::cerr << " No Gimbal Yaw found in XMP data of " << entry.path ().string () << std::endl;
738+ se.skyTrueNorth = 0.0 ;
739+ }
740+ else
741+ {
742+ gimbalYaw = xmpData[" Xmp.drone-dji.GimbalYawDegree" ].toFloat ();
743+ se.skyTrueNorth = gimbalYaw;
744+ if (se.skyTrueNorth < -180.0 )
745+ se.skyTrueNorth += 360.0 ;
746+ else if (se.skyTrueNorth > 180.0 )
747+ se.skyTrueNorth -= 360.0 ;
748+ }
749+ auto FlightYawIt = xmpData.findKey (Exiv2::XmpKey (" Xmp.drone-dji.FlightYawDegree" ));
750+ if (FlightYawIt == xmpData.end ())
751+ {
752+ std::cerr << " No Flight Yaw found in XMP data of " << entry.path ().string () << std::endl;
753+ }
754+ else
755+ {
756+ flightYaw = xmpData[" Xmp.drone-dji.FlightYawDegree" ].toFloat ();
757+ se.skyTrueNorth = flightYaw;
758+ if (se.skyTrueNorth < -180.0 )
759+ se.skyTrueNorth += 360.0 ;
760+ else if (se.skyTrueNorth > 180.0 )
761+ se.skyTrueNorth -= 360.0 ;
762+ }
696763 }
764+ cout << " Exiv2: Parsed EXIF for " << entry.path ().string () << " : Longitude=" << se.skyLongitude << " , Latitude=" << se.skyLatitude << endl;
765+ cout << " XMP: Parsed Gimbal Yaw for " << entry.path ().string () << " : GimbalYawDegree=" << gimbalYaw << endl;
766+ cout << " XMP: Parsed Flight Yaw for " << entry.path ().string () << " : FlightYawDegree=" << flightYaw << endl;
697767 }
698768 skyEntries.push_back (se);
699769 skys->append (se.name );
@@ -720,7 +790,7 @@ bool GeoDataLoader::init()
720790
721791 float farValue = coVRConfig::instance ()->farClip ();
722792 float scale = (farValue * 2 ) / 20000 ;
723- skyRootNode->setMatrix (osg::Matrix::scale (scale, scale, scale) * osg::Matrix::rotate (northAngle, osg::Vec3 (0 , 0 , 1 )));
793+ skyRootNode->setMatrix (osg::Matrix::scale (scale, scale, scale) * osg::Matrix::rotate (northAngle + osg::DegreesToRadians ( 90.0 ) , osg::Vec3 (0 , 0 , - 1 )));
724794
725795 skyNorthSlider = new ui::Slider (skyGroup, " skyNorth" );
726796 skyNorthSlider->setText (" Sky True North (°)" );
@@ -731,7 +801,7 @@ bool GeoDataLoader::init()
731801 northAngle = osg::DegreesToRadians (value);
732802 float farValue = coVRConfig::instance ()->farClip ();
733803 float scale = (farValue * 2 ) / 20000 ;
734- skyRootNode->setMatrix (osg::Matrix::scale (scale, scale, scale)*osg::Matrix::rotate (northAngle, osg::Vec3 (0 ,0 ,1 ))); });
804+ skyRootNode->setMatrix (osg::Matrix::scale (scale, scale, scale)*osg::Matrix::rotate (northAngle + osg::DegreesToRadians ( 90.0 ), osg::Vec3 (0 ,0 ,- 1 ))); });
735805
736806 locationGroup = new ui::Group (geoDataMenu, " locationGroup" );
737807 locationGroup->setText (" Location" );
@@ -868,9 +938,9 @@ void GeoDataLoader::setSky(int selection)
868938 skyRootNode->addChild (sky.skyNode );
869939 }
870940 currentSkyNode = sky.skyNode ;
871- northAngle = sky.skyTrueNorth ;
941+ northAngle = osg::DegreesToRadians ( sky.skyTrueNorth ) ;
872942 if (skyNorthSlider != nullptr )
873- skyNorthSlider->setValue (osg::RadiansToDegrees (northAngle) );
943+ skyNorthSlider->setValue (sky. skyTrueNorth );
874944 }
875945}
876946
@@ -938,15 +1008,15 @@ bool GeoDataLoader::update()
9381008 // skyRootNode->setMatrix(osg::Matrix::scale(1000, 1000, 1000) * osg::Matrix::rotate(northAngle, osg::Vec3(0, 0, 1)));
9391009 float farValue = coVRConfig::instance ()->farClip ();
9401010 float scale = ((farValue) / 20000 ) + 500 ; // scale the sphere so that it stays a bit closer than the far clipping plane.
941- skyRootNode->setMatrix (osg::Matrix::scale (scale, scale, scale) * osg::Matrix::rotate (northAngle, osg::Vec3 (0 , 0 , 1 )) * osg::Matrix::rotate (cover->getObjectsXform ()->getMatrix ().getRotate ()));
1011+ skyRootNode->setMatrix (osg::Matrix::scale (scale, scale, scale) * osg::Matrix::rotate (northAngle + osg::DegreesToRadians ( 90.0 ) , osg::Vec3 (0 , 0 , - 1 )) * osg::Matrix::rotate (cover->getObjectsXform ()->getMatrix ().getRotate ()));
9421012 if (editInteraction->isRunning ())
9431013 {
9441014
9451015 // get the intersected node
9461016 if (cover->getIntersectedNode ())
9471017 {
9481018 // position label with name
949- // nameLabel_->setPosition(cover->getIntersectionHitPointWorld());
1019+ // nameLabel_->setPosition(cover->getIntersectionHitPointWorld());
9501020 if (cover->getIntersectedNode () != oldIntersectedNode)
9511021 {
9521022 // get the node name
0 commit comments