From 1156ec6c42b2177423961b95e4c47928909f932f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A9dric=20Traizet?= <cedric.traizet@c-s.fr>
Date: Tue, 13 Oct 2020 17:05:37 +0200
Subject: [PATCH] ENH: parse RPCs in IkonosMetadataInterface

---
 .../include/otbIkonosImageMetadataInterface.h |  2 +
 .../src/otbIkonosImageMetadataInterface.cxx   | 38 +++++++++++++
 .../src/otbImageMetadataInterfaceBase.cxx     | 53 +++++++++++++++----
 3 files changed, 82 insertions(+), 11 deletions(-)

diff --git a/Modules/Core/Metadata/include/otbIkonosImageMetadataInterface.h b/Modules/Core/Metadata/include/otbIkonosImageMetadataInterface.h
index 10091e070c..ced1df394f 100644
--- a/Modules/Core/Metadata/include/otbIkonosImageMetadataInterface.h
+++ b/Modules/Core/Metadata/include/otbIkonosImageMetadataInterface.h
@@ -136,6 +136,8 @@ public:
      * There values a computed by 6S. */
   WavelengthSpectralBandVectorType GetSpectralSensitivity() const override;
 
+  void Parse(const MetadataSupplierInterface *) override;
+
 protected:
   IkonosImageMetadataInterface();
   ~IkonosImageMetadataInterface() override
diff --git a/Modules/Core/Metadata/src/otbIkonosImageMetadataInterface.cxx b/Modules/Core/Metadata/src/otbIkonosImageMetadataInterface.cxx
index 7bd28780cd..60f69b2b76 100644
--- a/Modules/Core/Metadata/src/otbIkonosImageMetadataInterface.cxx
+++ b/Modules/Core/Metadata/src/otbIkonosImageMetadataInterface.cxx
@@ -786,4 +786,42 @@ IkonosImageMetadataInterface::WavelengthSpectralBandVectorType IkonosImageMetada
   return wavelengthSpectralBand;
 }
 
+
+namespace
+{
+  struct IkonosMetadata
+  {
+    double sunAzimuth;
+
+  }
+
+}
+
+void IkonosImageMetadataInterface::Parse(const MetadataSupplierInterface *mds)
+{
+  assert(mds);
+
+  std::cout << "IkonosImageMetadataInterface::Parse " << std::endl;
+
+  bool hasValue = 0;
+
+  auto metadatatype = mds->GetMetadataValue("METADATATYPE", hasValue);
+  if (!hasValue || metadatatype != "GE")
+  {
+    otbGenericExceptionMacro(MissingMetadataException, 
+      << "No Geo-Eye metadata has been found")
+  }
+
+
+  auto inputFilename = mds->GetResourceFile();
+  auto fileNames = mds->GetResourceFiles();
+  for (const auto & filename: fileNames )
+  {
+    std::cout << filename << std::endl;
+  }
+
+  FetchRPC(*mds);
+  std::cout << m_Imd << std::endl;
+}
+
 } // end namespace otb
diff --git a/Modules/Core/Metadata/src/otbImageMetadataInterfaceBase.cxx b/Modules/Core/Metadata/src/otbImageMetadataInterfaceBase.cxx
index 7d662a217e..621d55cdd2 100644
--- a/Modules/Core/Metadata/src/otbImageMetadataInterfaceBase.cxx
+++ b/Modules/Core/Metadata/src/otbImageMetadataInterfaceBase.cxx
@@ -692,17 +692,48 @@ const boost::any& ImageMetadataInterfaceBase::FetchRPC(
   const MetadataSupplierInterface & mds)
 {
   Projection::RPCParam rpcStruct;
-  rpcStruct.LineOffset    = mds.GetAs<double>("RPC/LINE_OFF");
-  rpcStruct.SampleOffset  = mds.GetAs<double>("RPC/SAMP_OFF");
-  rpcStruct.LatOffset     = mds.GetAs<double>("RPC/LAT_OFF");
-  rpcStruct.LonOffset     = mds.GetAs<double>("RPC/LONG_OFF");
-  rpcStruct.HeightOffset  = mds.GetAs<double>("RPC/HEIGHT_OFF");
-
-  rpcStruct.LineScale    = mds.GetAs<double>("RPC/LINE_SCALE");
-  rpcStruct.SampleScale  = mds.GetAs<double>("RPC/SAMP_SCALE");
-  rpcStruct.LatScale     = mds.GetAs<double>("RPC/LAT_SCALE");
-  rpcStruct.LonScale     = mds.GetAs<double>("RPC/LONG_SCALE");
-  rpcStruct.HeightScale  = mds.GetAs<double>("RPC/HEIGHT_SCALE");
+
+  // In some products, RPC metadata read by GDAL have an unit attached, and the
+  // fetched string cannot be converted to double directly, e.g.
+  // LINE_OFF=+002320.00 pixels (from an Ikonos product)
+  // This lambda removes the unit suffix from the metadata.
+  auto GetMetadataWithoutUnit = [](const std::string & path, 
+                                    const MetadataSupplierInterface & mds)
+  {
+    const std::vector<std::string> unitNames = {"meters", "degrees", "pixels"};
+    auto metadataAsString = mds.GetAs<std::string>(path);
+
+    for (const auto & name : unitNames)
+    {
+      auto i = metadataAsString.find(name);
+      if (i != std::string::npos)
+      {
+        metadataAsString.erase(i, name.size());
+        break;
+      }
+    }
+    
+    try
+    {
+      return std::stod(metadataAsString);
+    }
+    catch (const std::invalid_argument&)
+    {
+      otbGenericExceptionMacro(MissingMetadataException,<<"Bad metadata value for '"<<path<<"', got: "<<metadataAsString)
+    }
+  };
+
+  rpcStruct.LineOffset    = GetMetadataWithoutUnit("RPC/LINE_OFF", mds);
+  rpcStruct.SampleOffset  = GetMetadataWithoutUnit("RPC/SAMP_OFF", mds);
+  rpcStruct.LatOffset     = GetMetadataWithoutUnit("RPC/LAT_OFF", mds);
+  rpcStruct.LonOffset     = GetMetadataWithoutUnit("RPC/LONG_OFF", mds);
+  rpcStruct.HeightOffset  = GetMetadataWithoutUnit("RPC/HEIGHT_OFF", mds);
+
+  rpcStruct.LineScale    = GetMetadataWithoutUnit("RPC/LINE_SCALE", mds);
+  rpcStruct.SampleScale  = GetMetadataWithoutUnit("RPC/SAMP_SCALE", mds);
+  rpcStruct.LatScale     = GetMetadataWithoutUnit("RPC/LAT_SCALE", mds);
+  rpcStruct.LonScale     = GetMetadataWithoutUnit("RPC/LONG_SCALE", mds);
+  rpcStruct.HeightScale  = GetMetadataWithoutUnit("RPC/HEIGHT_SCALE", mds);
 
   std::vector<double> coeffs(20);
 
-- 
GitLab