diff --git a/Code/UtilitiesAdapters/OGRAdapters/CMakeLists.txt b/Code/UtilitiesAdapters/OGRAdapters/CMakeLists.txt index 4ae9bf2e64aa7b4838ea67cff1b2a1d962373eea..e14833d7f635c032d142f22feb3d6662f418d1f3 100644 --- a/Code/UtilitiesAdapters/OGRAdapters/CMakeLists.txt +++ b/Code/UtilitiesAdapters/OGRAdapters/CMakeLists.txt @@ -25,10 +25,11 @@ ENDIF(NOT OTB_INSTALL_NO_LIBRARIES) # Note: no txx allowed here IF(NOT OTB_INSTALL_NO_DEVELOPMENT) FILE(GLOB __files1 "${CMAKE_CURRENT_SOURCE_DIR}/*.h") - # FILE(GLOB __files2 "${CMAKE_CURRENT_SOURCE_DIR}/*.txx") + FILE(GLOB __files2 "${CMAKE_CURRENT_SOURCE_DIR}/*.txx") # FILE(GLOB __files3 "${CMAKE_CURRENT_BINARY_DIR}/*.h") # INSTALL(FILES ${__files1} ${__files2} ${__files3} - INSTALL(FILES ${__files1} + # INSTALL(FILES ${__files1} + INSTALL(FILES ${__files1} ${__files2} DESTINATION ${OTB_INSTALL_INCLUDE_DIR_CM24}/UtilitiesAdapters/OGRAdapters COMPONENT Development) ENDIF(NOT OTB_INSTALL_NO_DEVELOPMENT) diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.cxx b/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.cxx index 73bd76797e1411bcfb399ba989e10ee6b49dab5c..6203f876bcbeb8cce565ae14931ce8df7b1c540f 100644 --- a/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.cxx +++ b/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.cxx @@ -199,12 +199,57 @@ OGRLayer* otb::ogr::DataSource::GetLayerUnchecked(size_t i) return layer_ptr; } +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); +} + + +otb::ogr::Layer otb::ogr::DataSource::GetLayerChecked(std::string const& name) +{ + assert(m_DataSource && "Datasource not initialized"); + OGRLayer * layer_ptr = m_DataSource->GetLayerByName(name.c_str()); + if (!layer_ptr) + { + itkExceptionMacro( << "Cannot fetch any layer named <" << name + << "> in the OGRDataSource <" << m_DataSource->GetName() << ">."); + } + return otb::ogr::Layer(layer_ptr); +} + int otb::ogr::DataSource::GetLayersCount() const { assert(m_DataSource && "Datasource not initialized"); return m_DataSource->GetLayerCount(); } +otb::ogr::Layer otb::ogr::DataSource::ExecuteSQL( + std::string const& statement, + OGRGeometry * poSpatialFilter, + char const* pszDialect) +{ + assert(m_DataSource && "Datasource not initialized"); + OGRLayer * layer_ptr = m_DataSource->ExecuteSQL( + statement.c_str(), poSpatialFilter, pszDialect); + if (!layer_ptr) + { +#if defined(PREFER_EXCEPTION) + itkExceptionMacro( << "Unexpected error: cannot execute the SQL request <" << statement + << "> in the OGRDataSource <" << m_DataSource->GetName() << ">."); +#else + // Cannot use the deleter made for result sets obtained from + // OGRDataSource::ExecuteSQL because it checks for non-nullity.... + // *sigh* + return otb::ogr::Layer(0); +#endif + } + return otb::ogr::Layer(layer_ptr, m_DataSource); + +} + + /*===========================================================================*/ /*===============================[ features ]================================*/ /*===========================================================================*/ @@ -245,3 +290,20 @@ void otb::ogr::DataSource::PrintSelf( assert(! "Disabled to check if it makes sense..."); } +bool otb::ogr::DataSource::HasCapability(std::string const& capabilityName) +{ + assert(m_DataSource && "Datasource not initialized"); + return m_DataSource->TestCapability(capabilityName.c_str()); +} + +void otb::ogr::DataSource::SyncToDisk() +{ + assert(m_DataSource && "Datasource not initialized"); + const OGRErr res= m_DataSource->SyncToDisk(); + if (res != OGRERR_NONE) + { + itkExceptionMacro( << "Cannot flush the pending of the OGRDataSource <" + << m_DataSource->GetName() << ">."); + } +} + diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.h b/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.h index 9aa2e6a2a0023daf75425d50293a8837efce3b2b..f06e44e44252202536e2fe9372efbfdc3d2940f5 100644 --- a/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.h +++ b/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.h @@ -32,6 +32,7 @@ class OGRDataSource; class OGRLayer; class OGRSpatialReference; +class OGRGeometry; #include "ogr_core.h" // OGRwkbGeometryType namespace otb { namespace ogr { @@ -149,11 +150,16 @@ namespace otb { namespace ogr { * an encapsulation of OGR classes. In that particular case, it's an * encapsulation of \c OGRDataSource. * - * \note not meant to be inherited - * \note this class has an entity semantics: \em non-copyable, nor \em + * \note Not meant to be inherited + * \note This class has an entity semantics: \em non-copyable, nor \em * assignable. * \note \c OGRRegisterAll() is implicitly called on construction - * \internal as the class is not meant to be inherited, no new function is virtual. + * \internal As the class is not meant to be inherited, no new function is virtual. + * + * \note The following function haven't been encapsulated (yet?): + * - \c SetStyleTable() & \c GetStyleTable() + * - \c SetDriver() & \c GetDriver() + * - all functions related to the reference count. */ class DataSource : public itk::DataObject { @@ -281,9 +287,13 @@ namespace otb { namespace ogr { /** * Creates a new layer. * \param[in] name name for the layer - * \param poSpatialRef the coordinate system to use for the new layer, or NULL if no coordinate system is available. - * \param[in] eGType the geometry type for the layer. Use wkbUnknown if there are no constraints on the types geometry to be written. - * \param[in] papszOptions a StringList of name=value options. Options are driver specific. + * \param poSpatialRef the coordinate system to use for the new layer, + * or NULL if no coordinate system is available. + * \param[in] eGType the geometry type for the layer. Use wkbUnknown + * if there are no constraints on the types + * geometry to be written. + * \param[in] papszOptions a StringList of name=value options. Options are + * driver specific. * * \return a proxy on the \c OGRLayer created. * \throw itk::ExceptionObject in case the layer cannot be created on the @@ -353,7 +363,7 @@ namespace otb { namespace ogr { /** * Unchecked Accessor to a given layer. * \param[in] i index of the layer to access - * \return a reference to the layer requested. + * \return the layer requested. * \pre <tt>i < GetLayersCount()</tt>, an assertion will abort the program * otherwise. * \pre the layer must available, an assertion will abort the program @@ -362,11 +372,24 @@ namespace otb { namespace ogr { * \note Use \c GetLayerUnchecked() if invalid indices are programming * errors, or if null layers are to be expected. */ - Layer GetLayer(size_t i); - /**\copydoc otb::ogr::DataSource::GetLayer() + Layer GetLayer(size_t i); + /**\copydoc otb::ogr::DataSource::GetLayer(size_t) */ Layer const GetLayer(size_t i) const; + /** + * Unchecked Accessor to a given layer. + * \param[in] name name of the layer to search + * \return the layer requested, possibly a null one. + * \throw None + * \note Use \c GetLayerUnchecked(std::string const&) if you'd rather have + * an exception instead of testing whether the layer obtained is valid. + */ + Layer GetLayer(std::string const& name); + /**\copydoc otb::ogr::DataSource::GetLayer(std::string const&) + */ + Layer const GetLayer(std::string const& name) const; + /** * Checked Accessor to a given layer. * \param[in] i index of the layer to access @@ -381,6 +404,44 @@ namespace otb { namespace ogr { /**\copydoc otb::ogr::DataSource::GetLayerChecked() */ Layer const GetLayerChecked(size_t i) const; + + /** + * Checked Accessor to a given layer. + * \param[in] name name of the layer to search + * \return the layer requested, possibly a null one. + * \throw itk::ExceptionObject if there exist no layer by that name + * \note use \c GetLayer(std::string const&) if you'd rather test the + * obtained layer instead of catching an exception. + */ + Layer GetLayerChecked(std::string const& name); + /**\copydoc otb::ogr::DataSource::GetLayerChecked(std::string const&) + */ + Layer const GetLayerChecked(std::string const& name) const; + + /** + * Excecutes the statement.. + * \param[in] statement textual description of the SQL statement. + * \param[in] poSpatialFilter \c Geometry representing a spatial filter -- may be null. + * \param[in] pszDialect allows control of the statement dialect. If set to + * NULL, the OGR SQL engine will be used, except for + * RDBMS drivers that will use their dedicated SQL + * engine, unless OGRSQL is explicitely passed as the + * dialect. + * \return a new \c Layer that contains the matching \c Features. In case of + * error, or no matching result sets, a \em null Layer will be returned. + * Check for \¢ Layer's validity before doing anything else. + * \throw None even when there is an error -- OGR can not report errors, + * neither this wrapping. + * \note the returned \c Layer will be automatically collected on its + * destruction ; i.e. unlike OGR API, no need to explicitly call \c + * OGRDataSource::ReleaseResultSet(). + * \sa OGRDataSource::ExecuteSQL + */ + Layer ExecuteSQL( + std::string const& statement, + OGRGeometry * poSpatialFilter, + char const* pszDialect); + //@} @@ -391,9 +452,25 @@ namespace otb { namespace ogr { * boolean expression to be used in \c if tests. * \see <em>Imperfect C++</em>, Matthew Wilson, Addisson-Welsey, par 24.6 */ - operator int boolean ::* () const { + operator int boolean ::* () const + { return m_DataSource ? &boolean::i : 0; - } + } + + /** + * Flushes all changes to disk. + * \throw itd::ExceptionObject in case the flush operation failed. + * \sa OGRDataSource::SyncToDisk + */ + void SyncToDisk(); + + /** + * Returns whether a capability is avalaible. + * \param[in] capabilityName name of the capability to check. + * \throw None + * \sa OGRDataSource::TestCapability + */ + bool HasCapability(std::string const& capabilityName); /** Access to raw \c OGRDataSource. * This function provides an abstraction leak in case deeper control on the diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.txx b/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.txx index 885aa7970755454b807cb9fac33d7fe0861755c4..3a456ee029c0ff1e1ae60dcfb8f111b066232f51 100644 --- a/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.txx +++ b/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapper.txx @@ -52,6 +52,13 @@ otb::ogr::Layer const otb::ogr::DataSource::GetLayer(size_t i) const return const_cast <DataSource*>(this)->GetLayer(i); } +inline +otb::ogr::Layer const otb::ogr::DataSource::GetLayer(std::string const& name) const +{ + return const_cast <DataSource*>(this)->GetLayer(name); +} + + inline otb::ogr::Layer const otb::ogr::DataSource::GetLayerChecked(size_t i) const { diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbOGRFeatureWrapper.cxx b/Code/UtilitiesAdapters/OGRAdapters/otbOGRFeatureWrapper.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e8d10ad15b94001e5b8fa8a4772a1da32d54a48f --- /dev/null +++ b/Code/UtilitiesAdapters/OGRAdapters/otbOGRFeatureWrapper.cxx @@ -0,0 +1,81 @@ +/*========================================================================= + + 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 "otbOGRFeatureWrapper.h" +#include <boost/bind.hpp> +#include <boost/make_shared.hpp> +#include "ogr_feature.h" + +/*===========================================================================*/ +/*======================[ Construction / Destruction ]=======================*/ +/*===========================================================================*/ +otb::ogr::Feature::Feature(OGRFeatureDefn & definition) +: m_Feature( + OGRFeature::CreateFeature(&definition), + boost::bind(&OGRFeature::DestroyFeature, _1)) +{ + CheckInvariants(); +} + +otb::ogr::Feature::Feature(OGRFeature * feature) +{ + if (feature) + { + m_Feature.reset(feature, boost::bind(&OGRFeature::DestroyFeature, _1)); + } + // else default is perfect -> delete null +} + +otb::ogr::Feature::~Feature() +{ +} + +otb::ogr::Feature otb::ogr::Feature::clone() const +{ + CheckInvariants(); + const Feature res(m_Feature->Clone()); + return res; +} + +/*===========================================================================*/ +/*=================================[ Misc ]==================================*/ +/*===========================================================================*/ +void otb::ogr::Feature::PrintSelf(std::ostream & os, itk::Indent indent) const +{ + CheckInvariants(); + os << indent << "+"; + os << " " << m_Feature->GetFieldCount() << " fields\n"; +} + +bool otb::ogr::operator==(otb::ogr::Feature const& lhs, otb::ogr::Feature const& rhs) +{ + // special case: they may be null (end() mark) + + // OGR is not const correct ... + OGRFeature * l = const_cast<OGRFeature*>(lhs.m_Feature.get()); + OGRFeature * r = const_cast<OGRFeature*>(rhs.m_Feature.get()); + return + (l == r ) // incl. ==0 + || + (l && r && l->Equal(r)) // must be non-null to compare them with Equal + ; +} + diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbOGRFeatureWrapper.h b/Code/UtilitiesAdapters/OGRAdapters/otbOGRFeatureWrapper.h new file mode 100644 index 0000000000000000000000000000000000000000..8b84d43bbd53bbdd2ce778d17b601aac10cb005f --- /dev/null +++ b/Code/UtilitiesAdapters/OGRAdapters/otbOGRFeatureWrapper.h @@ -0,0 +1,80 @@ +/*========================================================================= + + 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 __otbOGRFeatureWrapper_h +#define __otbOGRFeatureWrapper_h + +// #include <iosfwd> // std::ostream& +#include <cassert> +#include <boost/shared_ptr.hpp> +#include "itkIndent.h" + +class OGRFeature; +class OGRGeometry; +class OGRFeatureDefn; + +namespace otb { +namespace ogr { +class Feature; +bool operator==(Feature const& lhs, Feature const& rhs); + +/**\ingroup Geometry + * \class Feature + * \invariant <tt>m_Feature != 0</tt> + */ +class Feature + { +public: + // no default constructor + Feature(OGRFeatureDefn & definition); + Feature(OGRFeature * feature); + ~Feature(); + + Feature clone() const; + void PrintSelf(std::ostream &os, itk::Indent indent) const; + + OGRFeature const& ogr() const + { + CheckInvariants(); + return *m_Feature; + } + OGRFeature & ogr() + { + CheckInvariants(); + return *m_Feature; + } + + friend bool otb::ogr::operator==(Feature const& lhs, Feature const& rhs); +private: + void CheckInvariants() const + { + assert(m_Feature && "OGRFeature can't be null"); + } + boost::shared_ptr<OGRFeature> m_Feature; + + }; + + +} // ogr namespace +} // otb namespace + + +#ifndef OTB_MANUAL_INSTANTIATION +// #include "otbOGRFeatureWrapper.txx" +#endif + +#endif // __otbOGRFeatureWrapper_h diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.cxx b/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.cxx index 8d65dde47dd70dc7b3433bf139ea4d146bebdccc..002235436b448e2327ff869c46b260b1a470a9c7 100644 --- a/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.cxx +++ b/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.cxx @@ -22,12 +22,12 @@ #include "otbOGRLayerWrapper.h" #include <cassert> #include <boost/bind.hpp> +#include <boost/range/algorithm.hpp> #include "ogrsf_frmts.h" // OGRDataSource & OGRLayer /*===========================================================================*/ -/*==============================[ other stuff ]==============================*/ +/*======================[ Construction & Destruction ]=======================*/ /*===========================================================================*/ - namespace { // Anonymous namespace /**\ingroup Geometry * Deleter for \c boost::shared_ptr<> that doesn't delete. @@ -53,12 +53,62 @@ otb::ogr::Layer::Layer(OGRLayer* layer, OGRDataSource* sourceInChargeOfLifeTime) // OGR always refuses "delete 0". *sigh* } +/*===========================================================================*/ +/*===============================[ Features ]================================*/ +/*===========================================================================*/ int otb::ogr::Layer::GetFeatureCount(bool doForceComputation) const { assert(m_Layer); return m_Layer->GetFeatureCount(doForceComputation); } +otb::ogr::Feature otb::ogr::Layer::GetNextFeature() +{ + assert(m_Layer && "OGRLayer not initialized"); + return m_Layer->GetNextFeature(); +} + +otb::ogr::Layer::iterator otb::ogr::Layer::begin() +{ + assert(m_Layer && "OGRLayer not initialized"); + m_Layer->ResetReading(); + return iterator(*this); +} + +otb::ogr::Layer::const_iterator otb::ogr::Layer::cbegin() const +{ + assert(m_Layer && "OGRLayer not initialized"); + m_Layer->ResetReading(); + return const_iterator(*const_cast <Layer*>(this)); +} + +void otb::ogr::Layer::CreateFeature(Feature feature) +{ + assert(m_Layer && "OGRLayer not initialized"); + m_Layer->CreateFeature(&feature.ogr()); +} + +void otb::ogr::Layer::DeleteFeature(long nFID) +{ + assert(m_Layer && "OGRLayer not initialized"); + m_Layer->DeleteFeature(nFID); +} + +otb::ogr::Feature otb::ogr::Layer::GetFeature(long nFID) +{ + assert(m_Layer && "OGRLayer not initialized"); + Feature feat = m_Layer->GetFeature(nFID); +} + +void otb::ogr::Layer::SetFeature(Feature feature) +{ + assert(m_Layer && "OGRLayer not initialized"); + m_Layer->SetFeature(&feature.ogr()); +} + +/*===========================================================================*/ +/*=================================[ Misc ]==================================*/ +/*===========================================================================*/ std::string otb::ogr::Layer::GetName() const { assert(m_Layer && "null layer"); @@ -76,8 +126,10 @@ void otb::ogr::Layer::PrintSelf(std::ostream& os, itk::Indent indent) const os << indent << "+"; if (m_Layer) // in case for odd reason the layer that should exist can't be found { - os << "Layer <" << m_Layer->GetName() << "\n"; - // + for each feature + os << "Layer <" << m_Layer->GetName() << ">\n"; + boost::for_each( // for each feature + *this, + boost::bind(&Feature::PrintSelf, _1, boost::ref(os), indent.GetNextIndent())); } else { @@ -85,3 +137,21 @@ void otb::ogr::Layer::PrintSelf(std::ostream& os, itk::Indent indent) const } } +/*===========================================================================*/ +/*============================[ Spatial Filter ]=============================*/ +/*===========================================================================*/ + +OGRGeometry const* otb::ogr::Layer::GetSpatialFilter() const +{ + assert(m_Layer && "OGRLayer not initialized"); + OGRGeometry* spatialFilter = m_Layer->GetSpatialFilter(); + return spatialFilter; +} + +void otb::ogr::Layer::SetSpatialFilter(OGRGeometry const* spatialFilter) +{ + assert(m_Layer && "OGRLayer not initialized"); + // const_cast because OGR is not 100% const-correct + m_Layer->SetSpatialFilter(const_cast <OGRGeometry*>(spatialFilter)); +} + diff --git a/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.h b/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.h index 25194448a3b4c9df72c86ff35b5547368ae4fc78..da27e849317e2e60093da9d18d13db8ea05fb11a 100644 --- a/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.h +++ b/Code/UtilitiesAdapters/OGRAdapters/otbOGRLayerWrapper.h @@ -1,18 +1,18 @@ /*========================================================================= - Program: ORFEO Toolbox - Language: C++ - Date: $Date$ - Version: $Revision$ +Program: ORFEO Toolbox +Language: C++ +Date: $Date$ +Version: $Revision$ - Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. - See OTBCopyright.txt for details. +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. +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 __otbLayer_h @@ -20,14 +20,19 @@ // #include <iosfwd> // std::ostream& #include <boost/shared_ptr.hpp> +// #include <boost/iterator/iterator_adaptor.hpp> +#include <boost/iterator/iterator_facade.hpp> +#include <boost/utility/enable_if.hpp> #include "itkIndent.h" -class OGRLayer; // fwd declaration +#include "otbOGRFeatureWrapper.h" +class OGRLayer; // fwd declarations class OGRDataSource; +class OGRGeometry; -namespace otb { namespace ogr -{ +namespace otb { namespace ogr { /**\ingroup Geometry - * \brief Layer of geometric objets. + * \class Layer + * \brief %Layer of geometric objets. * * It provides an encapsulation of OGR classes. In that particular case, it's an * encapsulation of \c OGRLayer. @@ -43,7 +48,7 @@ namespace otb { namespace ogr * \todo find a way to tell whether the related \c OGRDataSource was released */ class Layer -// : public itk::DataObject + // : public itk::DataObject { public: /**\name Standard class typedefs */ @@ -65,6 +70,9 @@ public: explicit Layer(OGRLayer* layer); Layer(OGRLayer* layer, OGRDataSource* sourceInChargeOfLifeTime); //@} + + /**\name Features collection */ + //@{ /** Returns the number of elements in the layer. * \param[in] doForceCompuation indicates whether the size shall be computed * even so it's expensive to do so. @@ -75,12 +83,22 @@ public: */ int GetFeatureCount(bool doForceComputation) const; + void CreateFeature(Feature feature); + void DeleteFeature(long nFID); + Feature GetFeature(long nFID); + void SetFeature(Feature feature); + //@} + + /** Returns the name given to the layer, if any. + */ std::string GetName() const; /** Prints self into stream. */ void PrintSelf(std::ostream& os, itk::Indent indent) const; + /**\copydoc operator int boolean ::* () const + */ struct boolean{ int i; }; /** Can the layer be used (ie not null). * @@ -88,9 +106,10 @@ public: * boolean expression to be used in \c if tests. * @see <em>Imperfect C++</em>, Matthew Wilson, Addisson-Welsey, par 24.6 */ - operator int boolean ::* () const { + operator int boolean ::* () const + { return m_Layer ? &boolean::i : 0; - } + } /** Access to raw \c OGRLayer. * This function provides an abstraction leak in case deeper control on the @@ -102,10 +121,72 @@ public: */ OGRLayer & ogr(); + /**\name Spatial filter property + * \internal the I/O geometry is an undeletable pointer, can be may be null. + * \todo we'll see later if a Geometry capsule is defined, or a + * \c nondeletable<> pointer type. + */ + //@{ + OGRGeometry const* GetSpatialFilter() const; + void SetSpatialFilter(OGRGeometry const* spatialFilter); + //@} + + /**\name Iteration */ + //@{ + template <class Value> class feature_iter + : public boost::iterator_facade<feature_iter<Value>, Value, boost::single_pass_traversal_tag> + { + struct enabler {}; + public: + feature_iter() + : m_Layer(0), m_Crt(0) {} + explicit feature_iter(otb::ogr::Layer & layer) + : m_Layer(&layer), m_Crt(layer.GetNextFeature()) {} + template <class OtherValue> feature_iter( + feature_iter<OtherValue> const& other, + typename boost::enable_if<boost::is_convertible<OtherValue*,Value*> + , enabler + >::type = enabler() + ) + : m_Layer(other.m_Layer), m_Crt(other.m_Crt) + {} + private: + friend class boost::iterator_core_access; + template <class> friend class feature_iter; + + template <class OtherValue> bool equal(feature_iter<OtherValue> const& other) const + { return other.m_Crt == m_Crt; } + void increment() + { + assert(m_Layer && "cannot increment end()"); + m_Crt = m_Layer->GetNextFeature(); + } + Value & dereference() const + { return m_Crt; } + + otb::ogr::Layer * m_Layer; + otb::ogr::Feature m_Crt; + }; + + template <class> friend class feature_iter; + typedef feature_iter<Feature > iterator; + typedef feature_iter<Feature const> const_iterator; + + const_iterator begin() const { return cbegin(); } + const_iterator end () const { return cend (); } + const_iterator cbegin() const ; + const_iterator cend() const { return iterator(); } + iterator begin() ; + iterator end() { return iterator(); } + //@} private: + Feature GetNextFeature(); /** Data implementation. - * \internal The actual %layer implementation belongs to the \c otb::Layer object. + * \internal + * The actual %layer implementation belongs to the \c otb::Layer object, + * unless this is the result of \c ExecuteSQL. In that case a deleter is set + * to correctly release the layer. */ boost::shared_ptr<OGRLayer> m_Layer; }; diff --git a/Testing/Code/UtilitiesAdapters/OGRAdapters/CMakeLists.txt b/Testing/Code/UtilitiesAdapters/OGRAdapters/CMakeLists.txt index 0546c835c6d860668f7018e6428ac9feb67a54b4..b89c1032c039813260e47d202dad87ad17b41ca6 100644 --- a/Testing/Code/UtilitiesAdapters/OGRAdapters/CMakeLists.txt +++ b/Testing/Code/UtilitiesAdapters/OGRAdapters/CMakeLists.txt @@ -4,7 +4,10 @@ SET(OGR_TESTS ${CXX_TEST_PATH}/otbOGRTests) SET(OGRCommon_SRC otbOGRDataSourceWrapperNew.cxx -# otbOGRDataSourceWrapperIO.cxx +) + +SET(OGRNon_UT_SRC +otbOGRDataSourceWrapperIO.cxx ) find_package(Boost COMPONENTS filesystem unit_test_framework) @@ -22,7 +25,6 @@ ENDIF(Boost_FOUND) IF (Boost_UNIT_TEST_FRAMEWORK_FOUND) OTB_ADD_EXECUTABLE(otbOGRTests "${OGRCommon_SRC}" "OTBIO;OTBTesting") - # TARGET_LINK_LIBRARIES(otbOGRTests OTBOGRAdapters OTBTesting itkvcl) TARGET_LINK_LIBRARIES(otbOGRTests OTBOGRAdapters OTBTesting ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} ) @@ -33,8 +35,12 @@ IF (Boost_UNIT_TEST_FRAMEWORK_FOUND) otbOGRDataSourceWrapperNew ) ENDIF(Boost_UNIT_TEST_FRAMEWORK_FOUND) -# ADD_TEST(coTuOGRDataSourceWrapperIO ${OGR_TESTS} - # otbOGRDataSourceWrapperIO -# ) + +OTB_ADD_EXECUTABLE(otbOGRTestsV "${OGRNon_UT_SRC}" "OTBIO;OTBTesting") +TARGET_LINK_LIBRARIES(otbOGRTestsV OTBOGRAdapters OTBTesting + ) +ADD_TEST(coTuOGRDataSourceWrapperIO ${OGR_TESTS_NON_UT} + otbOGRDataSourceWrapperIO + ) ENDIF( NOT OTB_DISABLE_CXX_TESTING AND BUILD_TESTING ) diff --git a/Testing/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapperIO.cxx b/Testing/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapperIO.cxx index 49d26d45f2c5fea01a7960a1b16f5ed48b286e95..a9aa4d2b96a7f4a2f4983a75fd2070c7454138fe 100644 --- a/Testing/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapperIO.cxx +++ b/Testing/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapperIO.cxx @@ -29,8 +29,8 @@ using namespace otb; /*===========================================================================*/ /*==============================[ other stuff ]==============================*/ /*===========================================================================*/ -int otbOGRDataSourceNew (int argc, char **argv) -// int main(int argc, char **argv) +// int otbOGRDataSourceNew (int argc, char **argv) +int main(int argc, char **argv) { if (argc <1) { @@ -43,5 +43,6 @@ int otbOGRDataSourceNew (int argc, char **argv) std::cout << "nb layers:\t" << ds->GetLayersCount() << std::endl; std::cout << "nb features(0):\t" << ds->Size(false) << std::endl; std::cout << "nb features(1):\t" << ds->Size(true) << std::endl; + ds->Print(std::cout); return EXIT_SUCCESS; } diff --git a/Testing/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapperNew.cxx b/Testing/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapperNew.cxx index 3e3f1786ff5d8037122766b7ab210175845bc90b..976a420ca8bf1efa749a86e718068d0dddd32865 100644 --- a/Testing/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapperNew.cxx +++ b/Testing/Code/UtilitiesAdapters/OGRAdapters/otbOGRDataSourceWrapperNew.cxx @@ -64,6 +64,12 @@ BOOST_AUTO_TEST_CASE(OGRDataSource_mem_add_n_del_layer) BOOST_CHECK_THROW(ds->GetLayerChecked(1), itk::ExceptionObject); BOOST_CHECK_EQUAL(l.GetName(), k_one); BOOST_CHECK_EQUAL(l0.GetName(), k_one); + BOOST_CHECK_EQUAL(l0.GetName(), k_one); + + BOOST_CHECK_EQUAL(ds->GetLayer(k_one).GetName(), k_one); + BOOST_CHECK_EQUAL(ds->GetLayerChecked(k_one).GetName(), k_one); + BOOST_ASSERT(! ds->GetLayer(k_two)); + BOOST_CHECK_THROW(ds->GetLayerChecked(k_two), itk::ExceptionObject); ogr::Layer l2 = ds -> CreateLayer(k_two); BOOST_CHECK_EQUAL(ds->GetLayersCount(), 2); @@ -71,6 +77,7 @@ BOOST_AUTO_TEST_CASE(OGRDataSource_mem_add_n_del_layer) BOOST_CHECK_EQUAL(ds->Size(true), 0); BOOST_CHECK_EQUAL(ds->GetLayer(0).GetName(), k_one); BOOST_CHECK_EQUAL(ds->GetLayer(1).GetName(), k_two); + BOOST_CHECK_EQUAL(ds->GetLayer(k_two).GetName(), k_two); BOOST_CHECK_THROW(ds->GetLayerChecked(2), itk::ExceptionObject); ds->DeleteLayer(0);