Commit c1f2bc01 authored by Cédric Traizet's avatar Cédric Traizet
Browse files

ENH: implements an observer pattern to keep track of DEM configuration changes...

ENH: implements an observer pattern to keep track of DEM configuration changes in GDALRPCTransformer
parent 86f4a8a5
......@@ -26,6 +26,34 @@
namespace otb
{
/** \class DEMObserverInterface
*
* \brief Observer design pattern to keep track of DEM configuration changes
* \ingroup OTBIOGDAL
*/
class DEMObserverInterface {
public:
virtual ~DEMObserverInterface() = default;
virtual void Update() = 0;
};
/** \class DEMSubjectInterface
*
* \brief Observer design pattern to keep track of DEM configuration changes
* \ingroup OTBIOGDAL
*/
class DEMSubjectInterface {
public:
virtual ~DEMSubjectInterface() = default;
virtual void AttachObserver(DEMObserverInterface *observer) = 0;
virtual void DetachObserver(DEMObserverInterface *observer) = 0;
virtual void Notify() const = 0;
};
/** \class DEMHandler
*
* \brief Single access point for DEM data retrieval
......@@ -67,7 +95,7 @@ namespace otb
*
* \ingroup OTBIOGDAL
*/
class DEMHandler
class DEMHandler : public DEMSubjectInterface
{
public:
using Self = DEMHandler;
......@@ -140,6 +168,16 @@ public:
/** Clear the DEM list and close all DEM datasets */
void ClearDEMs();
/** Add an element to the current list of observers. The obsever will be updated whenever the DEM configuration
is modified*/
void AttachObserver(DEMObserverInterface *observer) override {m_ObserverList.push_back(observer);};
/** Remove an element of the current list of observers. */
void DetachObserver(DEMObserverInterface *observer) override {m_ObserverList.remove(observer);};
/** Update all observers */
void Notify() const override;
/** Path to the in-memory vrt */
const std::string DEM_DATASET_PATH = "/vsimem/otb_dem_dataset.vrt";
......@@ -179,6 +217,8 @@ private:
/** Filename of the current geoid */
std::string m_GeoidFilename;
/** Observers on the DEM */
std::list<DEMObserverInterface *> m_ObserverList;
};
}
......
......@@ -23,6 +23,10 @@
#include "itkPoint.h"
#include "gdal_alg.h"
#include "otbDEMHandler.h"
#include <mutex>
namespace otb
{
/**
......@@ -44,7 +48,7 @@ namespace otb
* \ingroup OTBIOGDAL
*/
class GDALRPCTransformer
class GDALRPCTransformer : public DEMObserverInterface
{
public:
......@@ -198,19 +202,27 @@ protected:
*
* Called when performing a transformation and some options were modified.
*/
void Update();
void Update() override;
private:
/** Used to know if Update is required after a change in the options */
bool m_Modified = true;
/** The RPC model */
GDALRPCInfo m_GDALRPCInfo;
/** The options */
char ** m_Options = nullptr;
/** The error allowed in the iterative solution */
double m_PixErrThreshold = 0.1;
/** The transformer arguments */
void * m_TransformArg = nullptr;
/** Lock threads when instantiating the GDAL RPC transformer */
std::mutex m_Mutex;
};
}
#endif
......@@ -202,6 +202,13 @@ void DEMHandler::OpenDEMFile(const std::string& path)
GDALClose(close_me);
m_Dataset = static_cast<GDALDataset*>(GDALOpen(DEM_DATASET_PATH.c_str(), GA_ReadOnly));
m_DEMDirectories.push_back(path);
if(m_GeoidDS)
{
CreateShiftedDataset();
}
Notify();
}
void DEMHandler::OpenDEMDirectory(const std::string& DEMDirectory)
......@@ -250,6 +257,7 @@ void DEMHandler::OpenDEMDirectory(const std::string& DEMDirectory)
{
CreateShiftedDataset();
}
Notify();
}
bool DEMHandler::OpenGeoidFile(const std::string& geoidFile)
......@@ -277,6 +285,7 @@ bool DEMHandler::OpenGeoidFile(const std::string& geoidFile)
CreateShiftedDataset();
}
Notify();
return pbError;
}
......@@ -481,6 +490,7 @@ void DEMHandler::ClearDEMs()
// This will call GDALClose on all datasets
m_DatasetList.clear();
Notify();
}
void DEMHandler::SetDefaultHeightAboveEllipsoid(double height)
......@@ -488,6 +498,7 @@ void DEMHandler::SetDefaultHeightAboveEllipsoid(double height)
OssimDEMHandler::Instance()->SetDefaultHeightAboveEllipsoid(height);
m_DefaultHeightAboveEllipsoid = height;
Notify();
}
double DEMHandler::GetDefaultHeightAboveEllipsoid() const
......@@ -495,4 +506,12 @@ double DEMHandler::GetDefaultHeightAboveEllipsoid() const
return m_DefaultHeightAboveEllipsoid;
}
void DEMHandler::Notify() const
{
for (const auto & observer: m_ObserverList)
{
observer->Update();
}
};
} // namespace otb
......@@ -53,26 +53,7 @@ GDALRPCTransformer::GDALRPCTransformer(double LineOffset, double SampleOffset, d
this->m_GDALRPCInfo.dfMAX_LONG = 180.0;
this->m_GDALRPCInfo.dfMAX_LAT = 90.0;
auto & demHandler = otb::DEMHandler::GetInstance();
if (demHandler.GetDEMCount() > 0)
{
if (demHandler.GetGeoidFile().empty())
{
this->SetOption("RPC_DEM", demHandler.DEM_DATASET_PATH);
}
else
{
this->SetOption("RPC_DEM", demHandler.DEM_SHIFTED_DATASET_PATH);
}
this->SetOption("RPC_DEM_MISSING_VALUE", std::to_string(demHandler.GetDefaultHeightAboveEllipsoid()));
}
else
{
// RPC height is used as a constant height offset applied to all points in case no DEM is set.
this->SetOption("RPC_HEIGHT", std::to_string(demHandler.GetDefaultHeightAboveEllipsoid()));
}
otb::DEMHandler::GetInstance().AttachObserver(this);
this->SetOption("RPC_MAX_ITERATIONS", "40");
this->SetOption("RPC_PIXEL_ERROR_THRESHOLD", "0.000001");
......@@ -83,6 +64,8 @@ GDALRPCTransformer::~GDALRPCTransformer()
if(m_TransformArg != nullptr)
GDALDestroyTransformer(m_TransformArg);
CSLDestroy(m_Options);
otb::DEMHandler::GetInstance().DetachObserver(this);
}
void GDALRPCTransformer::SetOption(const std::string& Name, const std::string& Value)
......@@ -99,6 +82,29 @@ void GDALRPCTransformer::SetPixErrThreshold(double PixErrThreshold)
void GDALRPCTransformer::Update()
{
// We need a lock here because Update() is not called until the first call
// to Forward/InverseTransform(), which might be done in a thread.
const std::lock_guard<std::mutex> lock(m_Mutex);
auto & demHandler = otb::DEMHandler::GetInstance();
if (demHandler.GetDEMCount() > 0)
{
if (demHandler.GetGeoidFile().empty())
{
this->SetOption("RPC_DEM", demHandler.DEM_DATASET_PATH);
}
else
{
this->SetOption("RPC_DEM", demHandler.DEM_SHIFTED_DATASET_PATH);
}
this->SetOption("RPC_DEM_MISSING_VALUE", std::to_string(demHandler.GetDefaultHeightAboveEllipsoid()));
}
else
{
// RPC height is used as a constant height offset applied to all points in case no DEM is set.
this->SetOption("RPC_HEIGHT", std::to_string(demHandler.GetDefaultHeightAboveEllipsoid()));
}
if(m_TransformArg != nullptr)
GDALDestroyTransformer(m_TransformArg);
this->m_TransformArg = GDALCreateRPCTransformer(&this->m_GDALRPCInfo, false, this->m_PixErrThreshold, this->m_Options);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment