diff --git a/Code/Projections/CMakeLists.txt b/Code/Projections/CMakeLists.txt index 58723d4ecb824139d4a80b080f58a2e3400caf05..772742780d65cff7c2a5faaf2fc1a5e6bf33a3ef 100644 --- a/Code/Projections/CMakeLists.txt +++ b/Code/Projections/CMakeLists.txt @@ -6,7 +6,7 @@ IF( NOT OTB_USE_CURL ) ENDIF( NOT OTB_USE_CURL ) ADD_LIBRARY(OTBProjections ${OTBProjections_SRCS}) -TARGET_LINK_LIBRARIES(OTBProjections OTBIO) +TARGET_LINK_LIBRARIES(OTBProjections OTBIO OTBOGRAdapters) IF(OTB_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(OTBProjections PROPERTIES ${OTB_LIBRARY_PROPERTIES}) diff --git a/Code/Projections/otbGeometriesProjectionFilter.cxx b/Code/Projections/otbGeometriesProjectionFilter.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e1d579df013aaec7be3e51c92d082700e0937ec9 --- /dev/null +++ b/Code/Projections/otbGeometriesProjectionFilter.cxx @@ -0,0 +1,280 @@ +/*========================================================================= + + Program: ORFEO Toolbox + Language: C++ + Date: $Date$ + Version: $Revision$ + + + Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. + See OTBCopyright.txt for details. + + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +/*===========================================================================*/ +/*===============================[ Includes ]================================*/ +/*===========================================================================*/ +#include "otbGeometriesProjectionFilter.h" +#include <boost/type_traits/is_same.hpp> +#include <boost/mpl/assert.hpp> +#include "ogr_srs_api.h" // OCTDestroyCoordinateTransformation +#include "ogr_spatialref.h" // OGRCoordinateTransformation +#include "itkMacro.h" +#include "otbGeometriesSet.h" +#include "itkMetaDataObject.h" +#include "otbOGRGeometryWrapper.h" +#include "otbOGRGeometriesVisitor.h" + + +/*===========================================================================*/ +/*===============================[ constants ]===============================*/ +/*===========================================================================*/ +namespace +{ // Anonymous namespace +const double k_averageElevation = -32768.0; +} // Anonymous namespace + +/*===========================================================================*/ +/*======================[ Reprojection Transformation ]======================*/ +/*===========================================================================*/ + + +template <typename TGeometry> +otb::ogr::UniqueGeometryPtr +otb::ReprojectTransformationFunctor::ByCopy::operator()(TGeometry const* in) const +{ + boost::interprocess::unique_ptr<TGeometry, ogr::internal::GeometryDeleter> + out(in ? static_cast <TGeometry*>(in->clone()) : 0); // OGR clone doesn't use covariant return ... + if (out) + m_Reprojector.do_transform(*out); + ogr::UniqueGeometryPtr res(out.release()); + return boost::move(res); +} + +template <typename TGeometry> +void +otb::ReprojectTransformationFunctor::InPlace::operator()(TGeometry * inout) const +{ + if (inout) + m_Reprojector.do_transform(*inout); +} + +#if 0 +void do_transform(OGRLinearRing & g) const +{ + assert(!"don't know how to reproject a ring yet"); +} +#endif + +void otb::ReprojectTransformationFunctor::do_transform(OGRPoint & g) const +{ + typedef InternalTransformType::InputPointType InputPointType; + typedef InternalTransformType::OutputPointType OutputPointType; + // in our case: + BOOST_MPL_ASSERT((boost::is_same<InputPointType, OutputPointType>)); + const double rawPoint[] = { g.getX(), g.getY() }; + const InputPointType inPoint(rawPoint); + const OutputPointType outPoint = m_Transform->TransformPoint(inPoint); + g.setX(outPoint[0]); + g.setY(outPoint[1]); +} + +void otb::ReprojectTransformationFunctor::do_transform(OGRLineString & g) const +{ + OGRPoint point; + for (int i=0, N=g.getNumPoints(); i!=N; ++i) + { + g.getPoint(i, &point); + do_transform(point); // no need to go through the redispatch cycle + g.setPoint(i, &point); + } +} + +#if 0 +void otb::ReprojectTransformationFunctor::do_transform(OGRCurve & g) const +{ + assert(!"OGRCurve is just an interface, they can't be reprojected yet"); +} +#endif + +void otb::ReprojectTransformationFunctor::do_transform(OGRPolygon & g) const +{ + // Note: OGRPolygon interface states that rings obtained through + // getInteriorRing() and getExteriorRing() shall not be modified. + // In this context, it seems to make sense as it gives a direct access to the + // ring (yes this is a de-encapsulation), and the polygon is a fresh one has + // just been cloned in the () operator. + // The fact that OGRPolygon::transform() directly works on each sub-ring seems + // to confirm that hyppothesis. + for (int i=0, N=g.getNumInteriorRings(); i!=N; ++i) + { + OGRLinearRing * ring = g.getInteriorRing(i); + assert(ring && "Rings in polygons are not expected to be nil"); + if (ring) + { + do_transform(*ring); // no need to go through the redispatch cycle + // how to commit the change ? Are ring modifications automatically commited ? + } + } + OGRLinearRing * ring = g.getExteriorRing(); + assert(ring && "Rings in polygons are not expected to be nil"); + if (ring) + { + do_transform(*ring); // no need to go through the redispatch cycle + // how to commit the change ? Are ring modifications automatically commited ? + } +} + +#if 0 +void otb::ReprojectTransformationFunctor::do_transform(OGRSurface & g) const +{ + assert(!"OGRSurface is just an interface, they can't be reprojected yet"); +} + +void otb::ReprojectTransformationFunctor::do_transform(OGRMultiLineString & g) const +{ +} + +void otb::ReprojectTransformationFunctor::do_transform(OGRMultiPoint & g) const +{ +} + +void otb::ReprojectTransformationFunctor::do_transform(OGRMultiPolygon & g) const +{ +} +#endif + +void otb::ReprojectTransformationFunctor::do_transform(OGRGeometryCollection & col) const +{ + for (int i=0, N=col.getNumGeometries(); i!=N; ++i) + { + OGRGeometry * g = col.getGeometryRef(i); + assert(g && "geometries to transform shall not be null"); + apply_inplace(g); + } +} + +otb::ogr::UniqueGeometryPtr +otb::ReprojectTransformationFunctor::operator()(OGRGeometry const* in) const +// otb::ReprojectTransformationFunctor::apply(OGRGeometry const* in) const +{ + otb::ogr::UniqueGeometryPtr res + = ogr::apply<otb::ogr::UniqueGeometryPtr>(in, ByCopy(*this)); + return boost::move(res); +} + +void otb::ReprojectTransformationFunctor::apply_inplace(OGRGeometry * inout) const +{ + if (inout) + ogr::apply<void>(inout, InPlace(*this)); +} + +/*===========================================================================*/ +/*======================[ GeometriesProjectionFilter ]=======================*/ +/*===========================================================================*/ + +otb::GeometriesProjectionFilter::GeometriesProjectionFilter() +: InputImageReference(*this) +, OutputImageReference(*this) +{ +} + +/*virtual*/ +otb::GeometriesProjectionFilter::~GeometriesProjectionFilter() +{ +} + +/*virtual*/ +void otb::GeometriesProjectionFilter::GenerateOutputInformation(void) +{ + Superclass::GenerateOutputInformation(); + + OutputGeometriesType::Pointer output = this->GetOutput(); + itk::MetaDataDictionary& dict = output->GetMetaDataDictionary(); + + itk::EncapsulateMetaData<std::string>(dict, MetaDataKey::ProjectionRefKey, m_OutputProjectionRef); +} + +/*virtual*/ +void otb::GeometriesProjectionFilter::FinalizeInitialisation() +{ + m_Transform = InternalTransformType::New(); + + InputGeometriesType::ConstPointer input = this->GetInput(); + const itk::MetaDataDictionary& inputDict = input->GetMetaDataDictionary(); + OutputGeometriesType::Pointer output = this->GetOutput(); + itk::MetaDataDictionary& outputDict = output->GetMetaDataDictionary(); + + // m_Transform->SetInputDictionary(input->GetMetaDataDictionary()); + m_Transform->SetInputDictionary(inputDict); + m_Transform->SetOutputDictionary(output->GetMetaDataDictionary()); + + m_Transform->SetInputProjectionRef(m_InputProjectionRef); + m_Transform->SetOutputProjectionRef(m_OutputProjectionRef); + m_Transform->SetInputKeywordList(m_InputKeywordList); + m_Transform->SetOutputKeywordList(m_OutputKeywordList); + m_Transform->SetDEMDirectory(m_DEMDirectory); + m_Transform->SetGeoidFile(m_GeoidFile); + m_Transform->SetAverageElevation(k_averageElevation); + + m_Transform->SetInputSpacing(InputImageReference.GetSpacing()); + m_Transform->SetInputOrigin(InputImageReference.GetOrigin()); + m_Transform->SetOutputSpacing(OutputImageReference.GetSpacing()); + m_Transform->SetOutputOrigin(OutputImageReference.GetOrigin()); + + m_Transform->InstanciateTransform(); + + m_TransformationFunctor->SetOnePointTransformation(m_Transform); + + // retrieve the output projection ref + // if it is not specified and end up being geographic, + // only the m_Transform will know + m_OutputProjectionRef = m_Transform->GetOutputProjectionRef(); + + //If the projection information for the output is provided, propagate it + + if (m_OutputKeywordList.GetSize() != 0) + { + itk::EncapsulateMetaData<ImageKeywordlist>(outputDict, MetaDataKey::OSSIMKeywordlistKey, m_OutputKeywordList); + } + if (!m_OutputProjectionRef.empty()) + { + itk::EncapsulateMetaData<std::string>(outputDict, MetaDataKey::ProjectionRefKey, m_OutputProjectionRef); + } + output->SetImageReference(OutputImageReference); +} + +/*virtual*/ +OGRSpatialReference* otb::GeometriesProjectionFilter::DoDefineNewLayerSpatialReference( + ogr::Layer const& source) const +{ + if (!m_OutputProjectionRef.empty()) + { + char const* wkt_string = m_OutputProjectionRef.c_str(); + OGRSpatialReference * res = static_cast <OGRSpatialReference*>(OSRNewSpatialReference(wkt_string)); + return res; + } + else + { + return 0; + } +} + +/*virtual*/ +void otb::GeometriesProjectionFilter::DoProcessLayer(ogr::Layer const& source, ogr::Layer & destination) const +{ + // std::cout << "GPF::DoProcessLayer: L("<<source.GetName()<<") -> L("<<destination.GetName()<<") ...\n"; + if (source != destination) + { + m_TransformationFunctor(source, destination); // if TransformedElementType == layer + } + else + { + m_TransformationFunctor(destination); // if TransformedElementType == layer + } +} diff --git a/Code/Projections/otbGeometriesProjectionFilter.h b/Code/Projections/otbGeometriesProjectionFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..448b98b69ae7d7a134b91954ae6b49719a3adbc4 --- /dev/null +++ b/Code/Projections/otbGeometriesProjectionFilter.h @@ -0,0 +1,191 @@ +/*========================================================================= + + Program: ORFEO Toolbox + Language: C++ + Date: $Date$ + Version: $Revision$ + + + Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. + See OTBCopyright.txt for details. + + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __otbGeometriesProjectionFilter_h +#define __otbGeometriesProjectionFilter_h + +#include "otbGeometriesToGeometriesFilter.h" +#include "otbOGRGeometryWrapper.h" +#include "otbImageReference.h" +#include "itkTransform.h" +#include "otbGenericRSTransform.h" + +class OGRCoordinateTransformation; + +namespace otb +{ + +struct ReprojectTransformationFunctor +{ + typedef OGRGeometry TransformedElementType; + + struct ByCopy + { + ByCopy(ReprojectTransformationFunctor const& reprojector) : m_Reprojector(reprojector){} + template <typename TGeometry> + ogr::UniqueGeometryPtr operator()(TGeometry const* in) const; + private: + ReprojectTransformationFunctor const& m_Reprojector; + }; + + struct InPlace + { + InPlace(ReprojectTransformationFunctor const& reprojector) : m_Reprojector(reprojector){} + template <typename TGeometry> + void operator()(TGeometry * inout) const; + private: + ReprojectTransformationFunctor const& m_Reprojector; + }; + + + ogr::UniqueGeometryPtr operator()(OGRGeometry const* in) const; + // ogr::UniqueGeometryPtr apply(OGRGeometry const* in) const; + void apply_inplace (OGRGeometry * inout) const; + + typedef otb::GenericRSTransform<double, 2, 2> InternalTransformType; + typedef InternalTransformType::Pointer InternalTransformPointerType; + void SetOnePointTransformation(InternalTransformPointerType transform) + { + m_Transform = transform; + } +private: + void do_transform(OGRPoint & g) const; + // void do_transform(OGRLinearRing & g) const; + void do_transform(OGRLineString & g) const; + // void do_transform(OGRCurve & g) const; + void do_transform(OGRPolygon & g) const; +#if 0 + void do_transform(OGRSurface & g) const; + void do_transform(OGRMultiLineString & g) const; + void do_transform(OGRMultiPoint & g) const; + void do_transform(OGRMultiPolygon & g) const; +#endif + void do_transform(OGRGeometryCollection & g) const; + + InternalTransformPointerType m_Transform; +}; + + +class ITK_EXPORT GeometriesProjectionFilter : public GeometriesToGeometriesFilter +{ +public: + /**\name Standard ITK typedefs */ + //@{ + typedef GeometriesProjectionFilter Self; + typedef GeometriesToGeometriesFilter Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + //@} + + /**\name Standard macros */ + //@{ + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(GeometriesProjectionFilter, GeometriesToGeometriesFilter); + //@} + + /**\name I/O typedefs */ + //@{ + typedef Superclass::InputGeometriesType InputGeometriesType; + // typedef Superclass::InputGeometriesPointer InputGeometriesPointer; + typedef Superclass::OutputGeometriesType OutputGeometriesType; + // typedef Superclass::OutputGeometriesPointer OutputGeometriesPointer; + //@} + + /**\name Class typedefs */ + //@{ + typedef ogr::ImageReference<double> ImageReference; + //@} + +private: + virtual OGRSpatialReference* DoDefineNewLayerSpatialReference(ogr::Layer const& source) const; + virtual void DoProcessLayer(ogr::Layer const& source, ogr::Layer & destination) const; + virtual void FinalizeInitialisation(); + +protected: + /** Default constructor. */ + GeometriesProjectionFilter(); + /** Destructor. */ + virtual ~GeometriesProjectionFilter(); + + virtual void GenerateOutputInformation(void); + +public: + ImageReference InputImageReference; + ImageReference OutputImageReference; + + /**\name Keywords lists accessors and mutators */ + //@{ + itkGetMacro(InputKeywordList, ImageKeywordlist); + void SetInputKeywordList(const ImageKeywordlist& kwl) + { + this->m_InputKeywordList = kwl; + this->Modified(); + } + + itkGetMacro(OutputKeywordList, ImageKeywordlist); + void SetOutputKeywordList(const ImageKeywordlist& kwl) + { + this->m_OutputKeywordList = kwl; + this->Modified(); + } + //@} + + /**\name Projection references accessors and mutators */ + //@{ + itkSetStringMacro(InputProjectionRef); + itkGetStringMacro(InputProjectionRef); + + itkSetStringMacro(OutputProjectionRef); + itkGetStringMacro(OutputProjectionRef); + //@} +private: + /**\name Functor definition */ + //@{ + typedef ReprojectTransformationFunctor TransformationFunctorType; + typedef TransformationFunctorType::TransformedElementType TransformedElementType; + typedef TransformationFunctorDispatcher<TransformationFunctorType, TransformedElementType> + TransformationFunctorDispatcherType; + + TransformationFunctorDispatcherType m_TransformationFunctor; + //@} + + /**\name 1 Point Transformation definition */ + //@{ + typedef TransformationFunctorType::InternalTransformType InternalTransformType; + typedef TransformationFunctorType::InternalTransformPointerType InternalTransformPointerType; + + InternalTransformPointerType m_Transform; + //@} + + std::string m_InputProjectionRef; // in WKT format! + std::string m_OutputProjectionRef; // in WKT format! + ImageKeywordlist m_InputKeywordList; + ImageKeywordlist m_OutputKeywordList; + + std::string m_DEMDirectory; + std::string m_GeoidFile; +}; +} // end namespace otb + +#ifndef OTB_MANUAL_INSTANTIATION +// #include "otbGeometriesProjectionFilter.txx" +#endif + +#endif // __otbGeometriesProjectionFilter_h diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbGeometriesSet.cxx b/Code/UtilitiesAdapters/OGRAdapters/otbGeometriesSet.cxx index d2c268574357d89e971550077abac253ad2b44e6..c83078511eebf8c26dcd71dee8d0730c21df6867 100644 --- a/Code/UtilitiesAdapters/OGRAdapters/otbGeometriesSet.cxx +++ b/Code/UtilitiesAdapters/OGRAdapters/otbGeometriesSet.cxx @@ -58,17 +58,20 @@ otb::ogr::Layer & getRef(otb::ogr::Layer & layer) /*===========================================================================*/ otb::GeometriesSet::GeometriesSet() : m_geometriesSet(otb::ogr::DataSource::New()) +, m_ImageReference(*this) { } otb::GeometriesSet::GeometriesSet(ogr::DataSource::Pointer datasource) : m_geometriesSet(datasource) +, m_ImageReference(*this) { assert(datasource && "unexpected nil datasource"); } otb::GeometriesSet::GeometriesSet(ogr::Layer layer) : m_geometriesSet(layer) +, m_ImageReference(*this) { } @@ -148,3 +151,28 @@ void otb::GeometriesSet::PrintSelf(std::ostream& os, itk::Indent indent) const { this->apply(Printer(os, indent)); } + +/*===========================================================================*/ +/*=========================[ GetMetaDataDictionary ]=========================*/ +/*===========================================================================*/ +struct MetaDataDictionaryGetter : boost::static_visitor<itk::MetaDataDictionary&> +{ + itk::MetaDataDictionary& operator()(otb::ogr::Layer layer) const + { + return layer.GetMetaDataDictionary(); + } + itk::MetaDataDictionary& operator()(otb::ogr::DataSource::Pointer datasource) const + { + return datasource->GetMetaDataDictionary(); + } +}; + +itk::MetaDataDictionary & otb::GeometriesSet::GetMetaDataDictionary() +{ + return this->apply(MetaDataDictionaryGetter()); +} + +itk::MetaDataDictionary const& otb::GeometriesSet::GetMetaDataDictionary() const +{ + return const_cast <GeometriesSet *>(this)->GetMetaDataDictionary(); +} diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbGeometriesSet.h b/Code/UtilitiesAdapters/OGRAdapters/otbGeometriesSet.h index 4efc6f40936078b6e8380d1bf922e74cc7538240..ff613e85c2e41e57758e5b32c03efdbd7c383760 100644 --- a/Code/UtilitiesAdapters/OGRAdapters/otbGeometriesSet.h +++ b/Code/UtilitiesAdapters/OGRAdapters/otbGeometriesSet.h @@ -22,6 +22,12 @@ #include "itkDataObject.h" // #include "otbOGRLayerWrapper.h" #include "otbOGRDataSourceWrapper.h" +#include "otbImageReference.h" + +namespace itk +{ +class MetaDataDictionary; +} namespace otb { @@ -107,6 +113,23 @@ public: */ bool IsSet() const; + /**\name Meta data dictionary */ + //@{ + itk::MetaDataDictionary & GetMetaDataDictionary(); + itk::MetaDataDictionary const& GetMetaDataDictionary() const; + //@} + + /**\name Image reference (spacing + origin) */ + //@{ + typedef ogr::ImageReference<double> ImageReference; + /** imageReference setter. */ + void SetImageReference(ImageReference const& imageReference) + { m_ImageReference = imageReference; } + /** imageReference getter. */ + ImageReference const& GetImageReference() const + { return m_ImageReference; } + //@} + protected: /** Default constructor. * This actual geometries set is an in-memory \c otb::ogr::DataSource. @@ -130,6 +153,7 @@ protected: private: typedef boost::variant<ogr::DataSource::Pointer, ogr::Layer> AnyGeometriesSetType; AnyGeometriesSetType m_geometriesSet; + ImageReference m_ImageReference; }; } // end namespace otb diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbGeometriesToGeometriesFilter.cxx b/Code/UtilitiesAdapters/OGRAdapters/otbGeometriesToGeometriesFilter.cxx index 743d3e1596fcc1ea1c14e0e34457af2cd85b5fcb..44b89a5307fff917773872c7831e118fa08640bb 100644 --- a/Code/UtilitiesAdapters/OGRAdapters/otbGeometriesToGeometriesFilter.cxx +++ b/Code/UtilitiesAdapters/OGRAdapters/otbGeometriesToGeometriesFilter.cxx @@ -70,15 +70,19 @@ struct ProcessVisitor : boost::static_visitor<> assert(destination && "can't filter to a nil datasource"); // std::cout << "G2GF: Process Visitor: DS("<<source->ogr().GetName()<<") -> DS("<<destination->ogr().GetName()<<") ...\n"; for (otb::ogr::DataSource::const_iterator b = source->begin(), e = source->end() -; b != e -; ++b + ; b != e + ; ++b ) { otb::ogr::Layer const& sourceLayer = *b; assert(sourceLayer && "unexpected nil source layer"); // std::cout << "source layer name:" << sourceLayer.GetName() << "\n"; otb::ogr::Layer destLayer = destination->CreateLayer( - sourceLayer.GetName(), 0, sourceLayer.GetGeomType()); + sourceLayer.GetName(), + m_filter.DoDefineNewLayerSpatialReference(sourceLayer), + m_filter.DoDefineNewLayerGeometryType(sourceLayer), + otb::ogr::StringListConverter(m_filter.DoDefineNewLayerOptions(sourceLayer)).to_ogr() + ); // std::cout << "layer created!\n"; m_filter.DoProcessLayer(sourceLayer, destLayer); } @@ -148,6 +152,8 @@ void otb::GeometriesToGeometriesFilter::GenerateData(void ) { // std::cout << "G2GF::GenerateData\n"; this->AllocateOutputs(); + this->FinalizeInitialisation(); + InputGeometriesType::ConstPointer input = this->GetInput(); // assert(input && "Cann't filter to a nil geometries set"); OutputGeometriesType::Pointer output = this->GetOutput(); diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbGeometriesToGeometriesFilter.h b/Code/UtilitiesAdapters/OGRAdapters/otbGeometriesToGeometriesFilter.h index ae73da1c9c1f7e7c342effd1c81b25249d84b446..2354c8895534b251d42e88aea263baf7fb1713f2 100644 --- a/Code/UtilitiesAdapters/OGRAdapters/otbGeometriesToGeometriesFilter.h +++ b/Code/UtilitiesAdapters/OGRAdapters/otbGeometriesToGeometriesFilter.h @@ -71,6 +71,10 @@ private: void Process(OutputGeometriesType &inout); void Process(InputGeometriesType const& source, OutputGeometriesType &destination); virtual void DoProcessLayer(ogr::Layer const& source, ogr::Layer & destination) const=0; + virtual OGRSpatialReference* DoDefineNewLayerSpatialReference(ogr::Layer const& source) const { return 0; } + virtual OGRwkbGeometryType DoDefineNewLayerGeometryType(ogr::Layer const& source) const { return source.GetGeomType(); } + virtual std::vector<std::string> DoDefineNewLayerOptions(ogr::Layer const& source) const { return std::vector<std::string>(); } + virtual void FinalizeInitialisation() {} friend struct ::ProcessVisitor; }; @@ -85,6 +89,7 @@ struct TransformationFunctorDispatcher<TransformationFunctor, ogr::Layer> { typedef typename TransformationFunctor::TransformedElementType TransformedElementType; BOOST_MPL_ASSERT((boost::is_same<ogr::Layer, TransformedElementType>)); + TransformationFunctorDispatcher() { } TransformationFunctorDispatcher(TransformationFunctor functor) : m_functor(functor){ } void operator()(ogr::Layer const& in, ogr::Layer & out) const { @@ -94,6 +99,7 @@ struct TransformationFunctorDispatcher<TransformationFunctor, ogr::Layer> { m_functor(inout); } + TransformationFunctor * operator->() { return &m_functor; } private: TransformationFunctor m_functor; }; @@ -104,6 +110,7 @@ struct TransformationFunctorDispatcher<TransformationFunctor, OGRGeometry> { typedef typename TransformationFunctor::TransformedElementType TransformedElementType; BOOST_MPL_ASSERT((boost::is_same<OGRGeometry, TransformedElementType>)); + TransformationFunctorDispatcher() { } TransformationFunctorDispatcher(TransformationFunctor functor) : m_functor(functor){ } void operator()(ogr::Layer const& in, ogr::Layer & out) const @@ -137,6 +144,7 @@ struct TransformationFunctorDispatcher<TransformationFunctor, OGRGeometry> inout.SetFeature(feat); } } + TransformationFunctor * operator->() { return &m_functor; } private: TransformationFunctor m_functor; }; diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbGeometriesToGeometriesFilter.txx b/Code/UtilitiesAdapters/OGRAdapters/otbGeometriesToGeometriesFilter.txx index 76f76ab4af36e912a13c6792a66e80111ff289fa..f7c1230d6050a4f1bff54598d685de49245f51f9 100644 --- a/Code/UtilitiesAdapters/OGRAdapters/otbGeometriesToGeometriesFilter.txx +++ b/Code/UtilitiesAdapters/OGRAdapters/otbGeometriesToGeometriesFilter.txx @@ -27,7 +27,6 @@ template <class TransformationFunctor> inline otb::DefaultGeometriesToGeometriesFilter<TransformationFunctor>::DefaultGeometriesToGeometriesFilter() -: m_TransformationFunctor(TransformationFunctor()) {} template <class TransformationFunctor> diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbImageReference.h b/Code/UtilitiesAdapters/OGRAdapters/otbImageReference.h new file mode 100644 index 0000000000000000000000000000000000000000..78978b278cf7b9fe59a2ab99413889e34e1174c8 --- /dev/null +++ b/Code/UtilitiesAdapters/OGRAdapters/otbImageReference.h @@ -0,0 +1,171 @@ +/*========================================================================= + + Program: ORFEO Toolbox + Language: C++ + Date: $Date$ + Version: $Revision$ + + + Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. + See OTBCopyright.txt for details. + + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __otbImageReference_h +#define __otbImageReference_h + +#include "itkVector.h" +#include "itkPoint.h" +#include "itkMacro.h" + +namespace otb +{ +namespace ogr +{ +/**\ingroup gGeometry + * \class ImageReference + * \todo See how mix it with the \c otb::ogr::DataSource wrapper as it was + * with \c VectorData. + * \since OTB v 3.14.0 + */ +template <typename TPrecision> class ImageReference +{ +public: + typedef TPrecision PrecisionType; + enum { Dimension = 2 }; + /**\name Standard ITK typedefs */ + //@{ + itkTypeMacro(ImageReference, void); + bool GetDebug() const + { + return m_holder.GetDebug(); + } + //@} + /**\name Template-parameters typedefs */ + //@{ + typedef itk::Vector<PrecisionType, 2> SpacingType; + typedef itk::Point<PrecisionType, 2> OriginType; + typedef itk::Point<PrecisionType, 2> PointType; + //@} + + /** Default constructor. + * \post <tt>m_Spacing = {1,1}</tt> + * \post <tt>m_Origin = {0,0}</tt> + */ + ImageReference(itk::Object const& holder) + : m_holder(holder) + { + m_Spacing.Fill(1); + m_Origin.Fill(0); + } + /** Init constructor. + * \post <tt>m_Spacing = spacing</tt> + * \post <tt>m_Origin = origin</tt> + */ + ImageReference(SpacingType const& spacing, OriginType const& origin, itk::Object const& holder) + : m_holder(holder) , m_Spacing(spacing), m_Origin(origin) + { + } + + void Modified() const + { + m_holder.Modified(); + } + + /**\name Origin property + * Represents the origin of the geometries in the image coordinates system. + */ + //@{ + itkGetConstReferenceMacro(Origin, OriginType); //!< Origin getter. + itkSetMacro(Origin, OriginType); //!< Origin setter. + void SetOrigin(const TPrecision origin[Dimension]) //!< Origin setter. + { + const OriginType p(origin); + this->SetOrigin(p); + } + //@} + + /**\name Spacing property + * Spacing of the geometries to put in the corresponding image coordinates. + */ + //@{ + itkGetConstReferenceMacro(Spacing, SpacingType); //!< Spacing getter. + void SetSpacing(const SpacingType& spacing) //!< Spacing setter. + { + // itkDebugMacro("setting Spacing to " << spacing); + if (this->m_Spacing != spacing) + { + this->m_Spacing = spacing; + this->Modified(); + } + } + void SetSpacing(const TPrecision spacing[Dimension]) //!< Spacing setter. + { + const SpacingType s(spacing); + this->SetSpacing(s); + } + //@} + + /** + * Projects a point from the Data Source coordinates system to the image + * coordinates system. + * \param[in] point point in Data Source coordinates system + * \param[out] physicalPoint point in the image coordinates system. + * \throw None + */ + void TransformPointToPhysicalPoint(const PointType& point, PointType& physicalPoint) const + { + for (size_t i=0; i!=Dimension; ++i) + physicalPoint[i] = point[i] * m_Spacing[i] + m_Origin[i]; + } + + /** + * Projects a point from the Data Source coordinates system to the image + * coordinates system. + * \param[in] point point in Data Source coordinates system + * \return the point projected in the image coordinates system. + * \throw None + */ + void TransformPointToPhysicalPoint(const PointType& point) const + { + // why no loop on VDimension ? + PointType physicalPoint; + for (size_t i=0; i!=Dimension; ++i) + physicalPoint[i] = point[i] * m_Spacing[i] + m_Origin[i]; + return physicalPoint; + } + + /** + * Assignment operator. + * \param[in] rhs source data to be copied. + * \throw None + * \internal + * Required because of the hack to provide a \c GetDebug() function which is + * required by \c itkTypeMacro. + */ + ImageReference& operator=(ImageReference const& rhs) + { + m_Spacing = rhs.m_Spacing; + m_Origin = rhs.m_Origin; + return *this; + } + +private: + itk::Object const& m_holder; + SpacingType m_Spacing; + OriginType m_Origin; +}; + +} // ogr namespace + +} // end namespace otb + +#ifndef OTB_MANUAL_INSTANTIATION +// #include "otbImageReference.txx" +#endif + +#endif // __otbImageReference_h diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.cxx b/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.cxx index 54ccbc270a8d372bab8219713ab79f84a78530e7..be40fbd4436a2e6e08f8c9fa98572cc4f7f06f53 100644 --- a/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.cxx +++ b/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.cxx @@ -256,7 +256,7 @@ otb::ogr::Layer otb::ogr::DataSource::CreateLayer( << "> in the OGRDataSource file <" << m_DataSource->GetName() <<">: " << CPLGetLastErrorMsg()); } - Layer l(ol); + Layer l(ol, this); return l; } @@ -275,7 +275,7 @@ otb::ogr::Layer otb::ogr::DataSource::CopyLayer( << "> in the OGRDataSource file <" << m_DataSource->GetName() <<">: " << CPLGetLastErrorMsg()); } - Layer l(ol); + Layer l(ol, this); return l; } @@ -310,7 +310,7 @@ otb::ogr::Layer otb::ogr::DataSource::GetLayerChecked(size_t i) itkExceptionMacro( << "Unexpected error: cannot fetch " << i << "th layer in the OGRDataSource <" << m_DataSource->GetName() << ">: " << CPLGetLastErrorMsg()); } - return otb::ogr::Layer(layer_ptr); + return otb::ogr::Layer(layer_ptr, this); } OGRLayer* otb::ogr::DataSource::GetLayerUnchecked(size_t i) @@ -324,7 +324,7 @@ otb::ogr::Layer otb::ogr::DataSource::GetLayer(std::string const& name) { assert(m_DataSource && "Datasource not initialized"); OGRLayer * layer_ptr = m_DataSource->GetLayerByName(name.c_str()); - return otb::ogr::Layer(layer_ptr); + return otb::ogr::Layer(layer_ptr, this); } @@ -338,7 +338,7 @@ otb::ogr::Layer otb::ogr::DataSource::GetLayerChecked(std::string const& name) << "> in the OGRDataSource <" << m_DataSource->GetName() << ">: " << CPLGetLastErrorMsg()); } - return otb::ogr::Layer(layer_ptr); + return otb::ogr::Layer(layer_ptr, this); } int otb::ogr::DataSource::GetLayersCount() const @@ -364,7 +364,7 @@ otb::ogr::Layer otb::ogr::DataSource::ExecuteSQL( // Cannot use the deleter made for result sets obtained from // OGRDataSource::ExecuteSQL because it checks for non-nullity.... // *sigh* - return otb::ogr::Layer(0); + return otb::ogr::Layer(0, 0); #endif } return otb::ogr::Layer(layer_ptr, *m_DataSource); diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.h b/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.h index 78f976d352ef83cf638eb32303096d1e5f7bbbab..0745c971392a91cc94a9bf64c57f0bf899da45f4 100644 --- a/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.h +++ b/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.h @@ -27,8 +27,6 @@ #include <boost/type_traits/is_const.hpp> #include <boost/noncopyable.hpp> -#include "itkVector.h" -#include "itkPoint.h" #include "itkDataObject.h" #include "itkMacro.h" // itkNewMacro #include "itkObjectFactory.h" // that should have been included by itkMacro.h @@ -42,112 +40,6 @@ class OGRGeometry; // #include "ogr_core.h" // OGRwkbGeometryType, included from Layer namespace otb { namespace ogr { -/**\ingroup gGeometry - * \class ImageReference - * \todo See how mix it with the \c otb::ogr::DataSource wrapper as it was - * with \c VectorData. - * \since OTB v 3.14.0 - */ -template <typename TPrecision> class ImageReference - { -public: - typedef TPrecision PrecisionType; - enum { Dimension = 2 }; - /**\name Standard ITK typedefs */ - //@{ - //@} - /**\name Template-parameters typedefs */ - //@{ - typedef itk::Vector<PrecisionType, 2> SpacingType; - typedef itk::Point<PrecisionType, 2> OriginType; - typedef itk::Point<PrecisionType, 2> PointType; - //@} - - /** Default constructor. - * \post <tt>m_Spacing = {1,1}</tt> - * \post <tt>m_Origin = {0,0}</tt> - */ - ImageReference() - { - m_Spacing.Fill(1); - m_Origin.Fill(0); - } - /** Init constructor. - * \post <tt>m_Spacing = spacing</tt> - * \post <tt>m_Origin = origin</tt> - */ - ImageReference(SpacingType const& spacing, OriginType const& origin) - : m_Spacing(spacing), m_Origin(origin) - { - } - - /**\name Origin property - * Represents the origin of the geometries in the image coordinates system. - */ - //@{ - itkGetConstReferenceMacro(Origin, OriginType); //!< Origin getter. - itkSetMacro(Origin, OriginType); //!< Origin setter. - void SetOrigin(const TPrecision origin[Dimension]) //!< Origin setter. - { - const OriginType p(origin); - this->SetOrigin(p); - } - //@} - - /**\name Spacing property - * Spacing of the geometries to put in the corresponding image coordinates. - */ - //@{ - itkGetConstReferenceMacro(Spacing, SpacingType); //!< Spacing getter. - void SetSpacing(const SpacingType& spacing) //!< Spacing setter. - { - itkDebugMacro("setting Spacing to " << spacing); - if (this->m_Spacing != spacing) - { - this->m_Spacing = spacing; - this->Modified(); - } - } - void SetSpacing(const TPrecision spacing[Dimension]) //!< Spacing setter. - { - const SpacingType s(spacing); - this->SetSpacing(s); - } - //@} - - /** - * Projects a point from the Data Source coordinates system to the image - * coordinates system. - * \param[in] point point in Data Source coordinates system - * \param[out] physicalPoint point in the image coordinates system. - * \throw None - */ - void TransformPointToPhysicalPoint(const PointType& point, PointType& physicalPoint) const - { - for (size_t i=0; i!=Dimension; ++i) - physicalPoint[i] = point[i] * m_Spacing[i] + m_Origin[i]; - } - - /** - * Projects a point from the Data Source coordinates system to the image - * coordinates system. - * \param[in] point point in Data Source coordinates system - * \return the point projected in the image coordinates system. - * \throw None - */ - void TransformPointToPhysicalPoint(const PointType& point) const - { - // why no loop on VDimension ? - PointType physicalPoint; - for (size_t i=0; i!=Dimension; ++i) - physicalPoint[i] = point[i] * m_Spacing[i] + m_Origin[i]; - return physicalPoint; - } -private: - SpacingType m_Spacing; - OriginType m_Origin; - }; - /**\ingroup gGeometry * \class DataSource * \brief Collection of geometric objects. diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.txx b/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.txx index 5f336bab58b9824943bd9fccbc22a30e4b0a9a30..f56d3d5283bb3af4f29ab73f0dc5b10c17697610 100644 --- a/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.txx +++ b/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.txx @@ -50,7 +50,7 @@ otb::ogr::Layer otb::ogr::DataSource::GetLayer(size_t i) assert(int(i) < GetLayersCount() && "Out-of-range index"); OGRLayer * layer_ptr = GetLayerUnchecked(i); assert(layer_ptr && "No layer returned by OGR"); - return otb::ogr::Layer(layer_ptr); + return otb::ogr::Layer(layer_ptr, this); } inline @@ -123,7 +123,7 @@ Value otb::ogr::DataSource::layer_iter<Value>::dereference() const assert(m_DataSource && int(m_index) < m_DataSource->GetLayersCount() && "cannot dereference past end()"); - return Value(m_DataSource->GetLayerUnchecked(m_index)); + return Value(m_DataSource->GetLayerUnchecked(m_index), const_cast <DataSource*>(m_DataSource)); } diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbOGRGeometriesVisitor.h b/Code/UtilitiesAdapters/OGRAdapters/otbOGRGeometriesVisitor.h new file mode 100644 index 0000000000000000000000000000000000000000..1eec99f88921fdafe2ca2dd4ac8707b4a097726f --- /dev/null +++ b/Code/UtilitiesAdapters/OGRAdapters/otbOGRGeometriesVisitor.h @@ -0,0 +1,74 @@ +/*========================================================================= + + Program: ORFEO Toolbox + Language: C++ + Date: $Date$ + Version: $Revision$ + + + Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. + See OTBCopyright.txt for details. + + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __otbOGRGeometriesVisitor_h +#define __otbOGRGeometriesVisitor_h + +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/type_traits/remove_const.hpp> +#include "ogr_geometry.h" + +namespace otb +{ +namespace ogr +{ +template <typename Tin, typename Tout> +struct propagate_const +{ +typedef Tout type; +}; +template <typename Tin, typename Tout> +struct propagate_const<Tin const, Tout> +{ +typedef typename boost::add_const<Tout>::type type; +}; + +#define TRY_APPLY(TYPE, geometry, functor) \ +if (typename propagate_const<TGeometry, TYPE>::type * dc = dynamic_cast<typename propagate_const<TGeometry, TYPE>::type*>(geometry))\ +{\ + return functor(dc); \ +} + + +template <typename TResult, class TGeometry, typename TFunctor> +TResult apply(TGeometry * geometry, TFunctor functor) +{ + BOOST_MPL_ASSERT((boost::is_same<OGRGeometry, typename boost::remove_const<TGeometry>::type >)); + TRY_APPLY(OGRPoint, geometry, functor) + else TRY_APPLY(OGRLinearRing, geometry, functor) + else TRY_APPLY(OGRLineString, geometry, functor) + // else TRY_APPLY(OGRCurve, geometry, functor) + else TRY_APPLY(OGRPolygon, geometry, functor) + // else TRY_APPLY(OGRSurface, geometry, functor) + else TRY_APPLY(OGRMultiLineString, geometry, functor) + else TRY_APPLY(OGRMultiPoint, geometry, functor) + else TRY_APPLY(OGRMultiPolygon, geometry, functor) + else TRY_APPLY(OGRGeometryCollection, geometry, functor) + { + // functor(geometry); + } +} +} // ogr namespace + +} // end namespace otb + +#ifndef OTB_MANUAL_INSTANTIATION +// #include "otbOGRGeometriesVisitor.txx" +#endif + +#endif // __otbOGRGeometriesVisitor_h diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.cxx b/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.cxx index cbbe9192cc4d9e7315773d987f0daf52d66e9c18..37460f6b653224f14091d6279d3bcd4ffe5e149a 100644 --- a/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.cxx +++ b/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.cxx @@ -26,6 +26,8 @@ #include <boost/foreach.hpp> #include "ogrsf_frmts.h" // OGRDataSource & OGRLayer +#include "otbOGRDataSourceWrapper.h" + /*===========================================================================*/ /*======================[ Construction & Destruction ]=======================*/ /*===========================================================================*/ @@ -42,8 +44,9 @@ namespace { // Anonymous namespace } // Anonymous namespace -otb::ogr::Layer::Layer(OGRLayer* layer) +otb::ogr::Layer::Layer(OGRLayer* layer, DataSourcePtr datasource) : m_Layer(layer, LeaveAloneDeleter()) +, m_DataSource(datasource) { } @@ -330,3 +333,12 @@ bool otb::ogr::operator==(Layer const& lhs, Layer const& rhs) const bool equal = lhs.m_Layer.get() == rhs.m_Layer.get(); return equal; } + +itk::MetaDataDictionary & otb::ogr::Layer::GetMetaDataDictionary() +{ + if (!m_DataSource) + { + itkGenericExceptionMacro(<<"Cannot acces metadata dictionary from a layer constructed with an SQL request."); + } + return m_DataSource->GetMetaDataDictionary(); +} diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.h b/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.h index 9da06e1acbc935380a0f71bca3ac7e0dd2c18d4f..64d77f92a7fc23dbb422372be233da6efc78b00a 100644 --- a/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.h +++ b/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.h @@ -32,8 +32,14 @@ class OGRDataSource; class OGRGeometry; class OGRFeatureDefn; -namespace otb { namespace ogr { +namespace itk +{ +class MetaDataDictionary; +} // itk namespace + +namespace otb { namespace ogr { +class DataSource; class Layer; /**\ingroup gGeometry @@ -64,16 +70,20 @@ bool operator==(Layer const& lhs, Layer const& rhs); class Layer { public: - /**\name ITK class typedefs */ + /**\name ITK standard definitions */ //@{ typedef Layer Self; + itkTypeMacro(Layer, void); //@} + typedef itk::SmartPointer<DataSource> DataSourcePtr; + /**\name Construction */ //@{ /** * Init constructor with a layer owned by a DataSource. * \param layer \c OGRLayer instance that is owned by a DataSource. + * \param datasource Pointer to the actual data source. * \throw None * On destruction of the proxy class, the internal \c OGRLayer is left alone. * @@ -81,13 +91,15 @@ public: * is deleted, the layer won't be usable anymore. Unfortunatelly, there is no * mean to report this to this layer proxy. */ - explicit Layer(OGRLayer* layer); + Layer(OGRLayer* layer, DataSourcePtr datasource); /** * Init constructor for layers that need to be released. * \param layer \c OGRLayer owned by the client code. * \param sourceInChargeOfLifeTime reference to the actual \c OGRDataSource * that knows how to release the layer. + * \post In this case, \c m_datasource is left null: we suppose (for now, that + * the layer won't need access to the datasource meta-information). * * \throw None * \internal @@ -462,6 +474,12 @@ public: OGRwkbGeometryType GetGeomType() const; friend bool otb::ogr::operator==(Layer const& lhs, Layer const& rhs); + + /**\name Meta data dictionary */ + //@{ + itk::MetaDataDictionary & GetMetaDataDictionary(); + itk::MetaDataDictionary const& GetMetaDataDictionary() const; + //@} private: /** * Internal encapsulation of \c OGRLayer::GetNextFeature(). @@ -481,6 +499,11 @@ private: * to correctly release the layer. */ boost::shared_ptr<OGRLayer> m_Layer; + + /** Related DataSource. + * Needed to acces OTB meta informations. + */ + DataSourcePtr m_DataSource; }; inline bool operator!=(Layer const& lhs, Layer const& rhs) diff --git a/Examples/Filtering/CMakeLists.txt b/Examples/Filtering/CMakeLists.txt index e59c88e32f9858cb39a4d9b3bccbca41853133e6..655f8b3f5ab446ac27a7cfe13dabeabde547f4da 100644 --- a/Examples/Filtering/CMakeLists.txt +++ b/Examples/Filtering/CMakeLists.txt @@ -63,6 +63,9 @@ ITKCommon ITKBasicFilters) ADD_EXECUTABLE(GeometriesFilter GeometriesFilter.cxx) TARGET_LINK_LIBRARIES(GeometriesFilter OTBOGRAdapters) +ADD_EXECUTABLE(GeometriesChangeSpatialReference GeometriesChangeSpatialReference.cxx) +TARGET_LINK_LIBRARIES(GeometriesChangeSpatialReference OTBOGRAdapters) + IF(OTB_USE_MAPNIK) ADD_EXECUTABLE(RasterizationExample RasterizationExample.cxx) TARGET_LINK_LIBRARIES(RasterizationExample OTBCommon OTBIO OTBBasicFilters) diff --git a/Examples/Filtering/GeometriesChangeSpatialReference.cxx b/Examples/Filtering/GeometriesChangeSpatialReference.cxx new file mode 100644 index 0000000000000000000000000000000000000000..53dcf25ad3db8aad6725e54799adfba7c131c4e0 --- /dev/null +++ b/Examples/Filtering/GeometriesChangeSpatialReference.cxx @@ -0,0 +1,139 @@ +/*========================================================================= + + Program: ORFEO Toolbox + Language: C++ + Date: $Date$ + Version: $Revision$ + + + Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. + See OTBCopyright.txt for details. + + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +/*===========================================================================*/ +/*===============================[ Includes ]================================*/ +/*===========================================================================*/ +#include "otbGeometriesToGeometriesFilter.h" +#include <string> +#include <iostream> +#include "otbOGRDataSourceWrapper.h" +#include "otbGeometriesSet.h" +#include "otbOGRGeometryWrapper.h" + +/*===========================================================================*/ +/*=========================[ Reprojection functor ]==========================*/ +/*===========================================================================*/ +namespace internal +{ +struct CoordTranfoDeleter +{ + void operator()(OGRCoordinateTransformation *p); +}; +} // internal namespace + +struct ReprojectTransformationFunctor +{ + typedef OGRGeometry TransformedElementType; + + otb::ogr::UniqueGeometryPtr operator()(OGRGeometry const* in) const; + void setSpatialReferences(OGRSpatialReference & in, OGRSpatialReference & out); +private: + boost::interprocess::unique_ptr<OGRCoordinateTransformation, internal::CoordTranfoDeleter> m_reprojector; +}; + + +void internal::CoordTranfoDeleter::operator()(OGRCoordinateTransformation *p) +{ + OCTDestroyCoordinateTransformation(p); +} + +otb::ogr::UniqueGeometryPtr +ReprojectTransformationFunctor::operator()(OGRGeometry const* in) const +{ + otb::ogr::UniqueGeometryPtr out(in ? in->clone() : 0); + if (out) + { + const OGRErr err = out->transform(m_reprojector.get()); + if (!err != OGRERR_NONE) + { + itkGenericExceptionMacro(<< "Cannot reproject a geometry: " << CPLGetLastErrorMsg()); + } + } + else + return boost::move(out); +} + +void ReprojectTransformationFunctor::setSpatialReferences( + OGRSpatialReference & in, OGRSpatialReference & out) +{ + m_reprojector.reset(OGRCreateCoordinateTransformation(&in, &out)); +} + +/*===========================================================================*/ +/*=================================[ main ]==================================*/ +/*===========================================================================*/ +typedef otb::DefaultGeometriesToGeometriesFilter<ReprojectTransformationFunctor> FilterType; + +int main (int argc, char **argv) +{ + if (argc < 2) + { + std::cerr << argv[0] << " inputGeometriesFile [outputGeometriesFile]" << std::endl; + return EXIT_FAILURE; + } + try + { + const bool workingInplace = argc==2; + const bool outputIsStdout = !workingInplace && !strcmp(argv[2], "-"); + + const std::string inputFile = argv[1]; + const std::string outputFile = workingInplace ? argv[1] : argv[2]; + + otb::ogr::DataSource::Pointer input = otb::ogr::DataSource::New( + inputFile, + workingInplace ? otb::ogr::DataSource::Modes::write : otb::ogr::DataSource::Modes::read); + + otb::ogr::DataSource::Pointer output + = workingInplace ? input + : outputIsStdout ? 0 + : otb::ogr::DataSource::New( outputFile, otb::ogr::DataSource::Modes::write); + std::cout << "input: " << input -> ogr().GetName() << " should be: " << inputFile << "\n"; + if (output) + { + std::cout << "output: " << output -> ogr().GetName() << " should be: " << outputFile << "\n"; + } + // std::cout << "\n"; + + FilterType::Pointer filter = FilterType::New(); + if (!workingInplace) + { + otb::GeometriesSet::Pointer in_set = otb::GeometriesSet::New(input); + filter->SetInput(in_set); + } + if (output) + { + otb::GeometriesSet::Pointer out_set = otb::GeometriesSet::New(output); + filter->SetOutput(out_set); + out_set->Update(); + } + else + { + filter->UpdateOutputData(0); + assert(filter->GetOutput() && "output not set"); + filter->GetOutput()->Print(std::cout, 0); + } + + return EXIT_SUCCESS; + } + catch (std::exception const& e) + { + std::cerr << e.what() << "\n"; + } + return EXIT_FAILURE; +} diff --git a/Examples/Filtering/GeometriesFilter.cxx b/Examples/Filtering/GeometriesFilter.cxx index b05aea74a471e617659630ecf8daaca48112f0b6..a1c84487cafd1af15e42586f56454687a9684bb0 100644 --- a/Examples/Filtering/GeometriesFilter.cxx +++ b/Examples/Filtering/GeometriesFilter.cxx @@ -26,7 +26,7 @@ #include "otbGeometriesSet.h" /*===========================================================================*/ -/*==============================[ other stuff ]==============================*/ +/*=============================[ SwapXYFunctor ]=============================*/ /*===========================================================================*/ struct SwapXYFunctor { @@ -46,12 +46,16 @@ struct SwapXYFunctor } }; +/*===========================================================================*/ +/*=================================[ main ]==================================*/ +/*===========================================================================*/ +typedef otb::DefaultGeometriesToGeometriesFilter<SwapXYFunctor> FilterType; + int main (int argc, char **argv) { if (argc < 2) { - std::cerr << " inputGeometriesFile [outputGeometriesFile]" << std::endl; - // if outputGeometriesFile == "-", output == stdout + std::cerr << argv[0] << " inputGeometriesFile [outputGeometriesFile]" << std::endl; return EXIT_FAILURE; } try @@ -77,8 +81,7 @@ int main (int argc, char **argv) } // std::cout << "\n"; - otb::DefaultGeometriesToGeometriesFilter<SwapXYFunctor>::Pointer filter - = otb::DefaultGeometriesToGeometriesFilter<SwapXYFunctor>::New(); + FilterType::Pointer filter = FilterType::New(); if (!workingInplace) { otb::GeometriesSet::Pointer in_set = otb::GeometriesSet::New(input); diff --git a/Examples/Projections/CMakeLists.txt b/Examples/Projections/CMakeLists.txt index 6acebc2a08e1fda9d915b60ddb8d18a5e0769bac..e5ccd6763ea856de49ca9aca973be2577fd6a9f8 100644 --- a/Examples/Projections/CMakeLists.txt +++ b/Examples/Projections/CMakeLists.txt @@ -31,6 +31,9 @@ ENDIF( OTB_USE_CURL ) ADD_EXECUTABLE(VectorDataProjectionExample VectorDataProjectionExample.cxx ) TARGET_LINK_LIBRARIES(VectorDataProjectionExample OTBProjections OTBCommon OTBIO) +ADD_EXECUTABLE(GeometriesProjection GeometriesProjection.cxx ) +TARGET_LINK_LIBRARIES(GeometriesProjection OTBProjections OTBOGRAdapters) + ADD_EXECUTABLE(VectorDataExtractROIExample VectorDataExtractROIExample.cxx ) TARGET_LINK_LIBRARIES(VectorDataExtractROIExample OTBProjections OTBCommon OTBIO) @@ -113,6 +116,18 @@ ADD_TEST(prTeVectorDataProjectionExampleTest ${EXE_TESTS} ) ENDIF(OTB_DATA_USE_LARGEINPUT) +IF(OTB_DATA_USE_LARGEINPUT) +ADD_TEST(prTeGeometriesProjectionTest ${EXE_TESTS} + --compare-ogr ${TOL} + ${BASELINE}/vectorDataProjectionExample.shp + ${TEMP}/geometriesProjectionExample.shp + GeometriesProjectionTest + ${INPUTDATA}/Capitole-Shadows.kml + ${INPUTLARGEDATA}/QUICKBIRD/TOULOUSE/000000128955_01_P001_PAN/02APR01105228-P1BS-000000128955_01_P001.TIF + ${TEMP}/geometriesProjectionExample.shp +) +ENDIF(OTB_DATA_USE_LARGEINPUT) + IF(OTB_DATA_USE_LARGEINPUT) #TODO change the example by using a SPOT4 roamnia ADD_TEST(prTeEstimateRPCSensorModelExampleTest ${EXE_TESTS} diff --git a/Examples/Projections/GeometriesProjection.cxx b/Examples/Projections/GeometriesProjection.cxx new file mode 100644 index 0000000000000000000000000000000000000000..b0571f4bd29269f2f6cb7a8375f09759ab44c4ca --- /dev/null +++ b/Examples/Projections/GeometriesProjection.cxx @@ -0,0 +1,163 @@ +/*========================================================================= + + Program: ORFEO Toolbox + Language: C++ + Date: $Date$ + Version: $Revision$ + + + Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. + See OTBCopyright.txt for details. + + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +// Software Guide : BeginLatex +// +// Let's assume that you have a KML file (hence in geographical coordinates) +// that you would like to superpose to some image with a specific map projection. +// Of course, you could use the handy ogr2ogr tool to do that, but it won't +// integrate so seamlessly into your OTB application. +// +// You can also suppose that the image on which you want to superpose +// the data is not in a specific map projection but a raw image from a +// particular sensor. Thanks to OTB, the same code below will be able +// to do the appropriate conversion. +// +// This example demonstrates the use of the +// \doxygen{otb}{GeometriesProjectionFilter}. +// +// Software Guide : EndLatex + +#include "otbGeometriesProjectionFilter.h" +#include "otbGeometriesSet.h" +// #include "otbGeometriesFileReader.h" +// #include "otbGeometriesFileWriter.h" + +#include "otbImage.h" +#include "otbImageFileReader.h" + +int main(int argc, char* argv[]) +{ + + if (argc < 4) + { + std::cerr << argv[0] << + " <input vector filename> <input image name> <output vector filename>\n"; + + return EXIT_FAILURE; + } + + // Software Guide : BeginLatex + // + // Declare the vector data type that you would like to use in your + // application. + // + // Software Guide : EndLatex + + // Software Guide : BeginCodeSnippet + typedef otb::GeometriesSet InputGeometriesType; + typedef otb::GeometriesSet OutputGeometriesType; + // Software Guide : EndCodeSnippet + + // Software Guide : BeginLatex + // + // Declare and instantiate the vector data reader: + // \doxygen{otb}{GeometriesFileReader}. The call to the + // \code{UpdateOutputInformation()} method fill up the header information. + // + // Software Guide : EndLatex + + // Software Guide : BeginCodeSnippet + otb::ogr::DataSource::Pointer input = otb::ogr::DataSource::New( + argv[1], otb::ogr::DataSource::Modes::read); + InputGeometriesType::Pointer in_set = InputGeometriesType::New(input); + // Software Guide : EndCodeSnippet + + // Software Guide : BeginLatex + // + // We need the image only to retrieve its projection information, + // i.e. map projection or sensor model parameters. Hence, the image + // pixels won't be read, only the header information using the + // \code{UpdateOutputInformation()} method. + // + // Software Guide : EndLatex + + // Software Guide : BeginCodeSnippet + typedef otb::Image<unsigned short int, 2> ImageType; + typedef otb::ImageFileReader<ImageType> ImageReaderType; + ImageReaderType::Pointer imageReader = ImageReaderType::New(); + imageReader->SetFileName(argv[2]); + imageReader->UpdateOutputInformation(); + // Software Guide : EndCodeSnippet + + // Software Guide : BeginLatex + // + // The \doxygen{otb}{GeometriesProjectionFilter} will do the work of + // converting the vector data coordinates. It is usually a good idea + // to use it when you design applications reading or saving vector + // data. + // + // Software Guide : EndLatex + + // Software Guide : BeginCodeSnippet + typedef otb::GeometriesProjectionFilter GeometriesFilterType; + GeometriesFilterType::Pointer filter = GeometriesFilterType::New(); + // Software Guide : EndCodeSnippet + + // Software Guide : BeginLatex + // + // Information concerning the original projection of the vector data + // will be automatically retrieved from the metadata. Nothing else + // is needed from you: + // + // Software Guide : EndLatex + + // Software Guide : BeginCodeSnippet + filter->SetInput(in_set); + // Software Guide : EndCodeSnippet + + // Software Guide : BeginLatex + // + // Information about the target projection is retrieved directly from + // the image: + // + // Software Guide : EndLatex + + // Software Guide : BeginCodeSnippet + filter->SetOutputKeywordList(imageReader->GetOutput()->GetImageKeywordlist()); // nec qd capteur + filter->OutputImageReference.SetOrigin(imageReader->GetOutput()->GetOrigin()); // nec qd capteur + filter->OutputImageReference.SetSpacing(imageReader->GetOutput()->GetSpacing()); // nec qd capteur + filter->SetOutputProjectionRef( imageReader->GetOutput()->GetProjectionRef()); // ~ wkt + // Software Guide : EndCodeSnippet + + // Software Guide : BeginLatex + // + // Finally, the result is saved into a new vector file. + // + // Software Guide : EndLatex + + // Software Guide : BeginCodeSnippet + otb::ogr::DataSource::Pointer output = otb::ogr::DataSource::New( + argv[3], otb::ogr::DataSource::Modes::write); + OutputGeometriesType::Pointer out_set = OutputGeometriesType::New(output); + + filter->SetOutput(out_set); + filter->Update(); + // Software Guide : EndCodeSnippet + + // Software Guide : BeginLatex + // + // It is worth noting that none of this code is specific to the + // vector data format. Whether you pass a shapefile, or a KML file, + // the correct driver will be automatically instantiated. + // + // Software Guide : EndLatex + + return EXIT_SUCCESS; + +} diff --git a/Examples/Projections/otbProjectionsExamplesTests.cxx b/Examples/Projections/otbProjectionsExamplesTests.cxx index 52de224b84605d29084c443f7dac918fda0377d4..9efea6a56135ad044e08315c9560cbed140b0d93 100644 --- a/Examples/Projections/otbProjectionsExamplesTests.cxx +++ b/Examples/Projections/otbProjectionsExamplesTests.cxx @@ -26,6 +26,7 @@ void RegisterTests() REGISTER_TEST(OrthoRectificationExampleTest); REGISTER_TEST(MapProjectionExampleTest); REGISTER_TEST(VectorDataProjectionExampleTest); + REGISTER_TEST(GeometriesProjectionTest); REGISTER_TEST(EstimateRPCSensorModelExample); } @@ -41,6 +42,10 @@ void RegisterTests() #define main VectorDataProjectionExampleTest #include "VectorDataProjectionExample.cxx" +#undef main +#define main GeometriesProjectionTest +#include "GeometriesProjection.cxx" + #undef main #define main EstimateRPCSensorModelExample #include "EstimateRPCSensorModelExample.cxx" diff --git a/Utilities/ITK/Code/Common/itkMetaDataObject.h b/Utilities/ITK/Code/Common/itkMetaDataObject.h index 45b04a2a14fbb7c7318a34687b1a0b6982020d35..fe6744eb3262698e9a27ae3e150b77dba381d60c 100644 --- a/Utilities/ITK/Code/Common/itkMetaDataObject.h +++ b/Utilities/ITK/Code/Common/itkMetaDataObject.h @@ -12,8 +12,8 @@ Portions of this code are covered under the VTK copyright. See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm for details. - This software is distributed WITHOUT ANY WARRANTY; without even - the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ @@ -128,7 +128,7 @@ public: virtual void Print(std::ostream& os) const; private: //This is made private to force the use of the MetaDataObject<MetaDataObjectType>::New() operator! - //void * operator new(size_t nothing) {};//purposefully not implemented + //void * operator new(size_t nothing) {}; //purposefully not implemented /** * \author Hans J. Johnson * A variable to store this derived type. @@ -176,9 +176,9 @@ inline bool ExposeMetaData(MetaDataDictionary &Dictionary, const std::string key { return false; } - + MetaDataObjectBase::Pointer baseObjectSmartPointer = Dictionary[key]; - + if(strcmp(typeid(T).name(),baseObjectSmartPointer->GetMetaDataObjectTypeName()) != 0) { return false;