diff --git a/Code/Common/otbVectorDataToImageFilter.h b/Code/Common/otbVectorDataToImageFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..9a240d0c32acd4fb4d18604867239210ca9a61bb --- /dev/null +++ b/Code/Common/otbVectorDataToImageFilter.h @@ -0,0 +1,229 @@ +/*========================================================================= + + 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 __otbVectorDataToImageFilter_h +#define __otbVectorDataToImageFilter_h + +#include "itkImageSource.h" +#include "otbRGBAPixelConverter.h" +#include "otbVectorDataExtractROI.h" +#include "otbRemoteSensingRegion.h" + +#include <mapnik/memory_datasource.hpp> +#include <mapnik/map.hpp> + +namespace otb +{ +/** \class VectorDataToImageFilter + * \brief <b>DEPRECATED</b>: See VectorDataToImageFilter + * \deprecated use VectorDataToImageFilter instead + * \sa VectorDataToImageFilter + */ + +template <class TVectorData, class TImage> +class ITK_EXPORT VectorDataToImageFilter : public itk::ImageSource<TImage> +{ +public: + /** Standard class typedefs. */ + typedef VectorDataToImageFilter Self; + typedef itk::ImageSource<TImage> Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(VectorDataToImageFilter, ImageSource); + + /** Some typedefs. */ + typedef TVectorData VectorDataType; + typedef TImage ImageType; + typedef typename ImageType::PixelType PixelType; + typedef typename ImageType::Pointer ImagePointer; + typedef typename VectorDataType::ConstPointer VectorDataConstPointer; + typedef typename VectorDataType::DataTreeType::TreeNodeType InternalTreeNodeType; + typedef typename InternalTreeNodeType::ChildrenListType ChildrenListType; + typedef VectorDataExtractROI<VectorDataType> VectorDataExtractROIType; + typedef RemoteSensingRegion<double> RemoteSensingRegionType; + typedef typename RemoteSensingRegionType::SizeType SizePhyType; + + /** Number of dimensions. */ + itkStaticConstMacro(ImageDimension, unsigned int, + TImage::ImageDimension); + + /** Image size typedef. */ + typedef itk::Size<itkGetStaticConstMacro(ImageDimension)> SizeType; + + /** Image index typedef. */ + typedef typename TImage::IndexType IndexType; + + /** Image spacing, origin and direction typedef */ + typedef typename TImage::SpacingType SpacingType; + typedef typename TImage::PointType OriginType; + typedef typename TImage::DirectionType DirectionType; + + /** Region typedef */ + typedef typename TImage::RegionType RegionType; + + /** RGBA Converter typedef */ + typedef RGBAPixelConverter<unsigned char, PixelType> RGBAConverterType; + + /** typedef specific to mapnik */ + typedef boost::shared_ptr<mapnik::memory_datasource> datasource_ptr; + + /** */ + typedef enum + { + OSM, + Binary + } RenderingStyleType; + + /** Set/Get the vector data input of this process object. */ + virtual void SetInput(const VectorDataType *input); + virtual void SetInput(unsigned int idx, const VectorDataType *input); + const VectorDataType * GetInput(void); + const VectorDataType * GetInput(unsigned int idx); + + /** Set the size of the output image. */ + itkSetMacro(Size, SizeType); + + /** Get the size of the output image. */ + itkGetConstReferenceMacro(Size, SizeType); + + /** Set the origin of the vector data. + * \sa GetOrigin() */ + itkSetMacro(Origin, OriginType); + virtual void SetOrigin(const double origin[2]); + virtual void SetOrigin(const float origin[2]); + + itkGetConstReferenceMacro(Origin, OriginType); + + /** Set the spacing (size of a pixel) of the vector data. + * \sa GetSpacing() */ + virtual void SetSpacing(const SpacingType& spacing); + virtual void SetSpacing(const double spacing[2]); + virtual void SetSpacing(const float spacing[2]); + + itkGetConstReferenceMacro(Spacing, SpacingType); + + /** Get/Set methods for the scale factor */ + itkSetMacro(ScaleFactor, double); + itkGetMacro(ScaleFactor, double); + + /** */ + void AddStyle(const std::string& style) + { + m_StyleList.push_back(style); + } + + /** Clear the style list */ + void ClearStyleList() + { + m_StyleList.clear(); + } + + /** Specify if the output image is to be uses as an overlar + * (with transparent background) or not (with blue background). + */ + itkSetMacro(UseAsOverlay, bool); + itkGetMacro(UseAsOverlay, bool); + itkBooleanMacro(UseAsOverlay); + + /** Get/Set methods for the rendering style type (OSM or Binary) */ + itkSetMacro(RenderingStyleType, RenderingStyleType); + itkGetMacro(RenderingStyleType, RenderingStyleType); + + /** Add accessors to the font filename */ + itkSetStringMacro(FontFileName); + itkGetStringMacro(FontFileName); + + /** Add accessors to the Projection in the WKT format */ + itkSetStringMacro(VectorDataProjectionWKT); + itkGetStringMacro(VectorDataProjectionWKT); + +protected: + /** Constructor */ + VectorDataToImageFilter(); + /** Destructor */ + virtual ~VectorDataToImageFilter() {} + /**PrintSelf method */ + virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; + + virtual void GenerateOutputInformation(); + + virtual void GenerateData(void); + + virtual void BeforeThreadedGenerateData(); + +private: + VectorDataToImageFilter(const Self &); //purposely not implemented + void operator =(const Self&); //purposely not implemented + + void ProcessNode(InternalTreeNodeType * source, datasource_ptr mDatasource); + + SpacingType m_Spacing; + OriginType m_Origin; + SizeType m_Size; + IndexType m_StartIndex; + DirectionType m_Direction; + + // font file name + std::string m_FontFileName; + + //This factor is used to flip the data on the Y axis when using a + //sensor model geometry (where the Y coordinate increases top-down) + int m_SensorModelFlip; + + //this parameter is used only in the case of sensor geometry + //to adjust the scale + double m_ScaleFactor; + + //style list + std::vector<std::string> m_StyleList; + + //Overlay option: change the backgroup (blue or transparent) + bool m_UseAsOverlay; + + //Projection in the proj.4 format (for mapnik) + std::string m_VectorDataProjectionProj4; + + //Projection in the WKT format + std::string m_VectorDataProjectionWKT; + + //Rendering style type + RenderingStyleType m_RenderingStyleType; + + //RGBA Converter + typename RGBAConverterType::Pointer m_RGBAConverter; + + //Internal Tiling + unsigned int m_NbTile; + std::vector<RegionType> m_TilingRegions; + std::vector<mapnik::Map> m_Maps; + std::vector< std::vector<typename VectorDataExtractROIType::Pointer> > + m_VectorDataExtractors; + +}; // end class +} // end namespace otb + +#ifndef OTB_MANUAL_INSTANTIATION +#include "otbVectorDataToImageFilter.txx" +#endif + +#endif diff --git a/Code/Common/otbVectorDataToImageFilter.txx b/Code/Common/otbVectorDataToImageFilter.txx new file mode 100644 index 0000000000000000000000000000000000000000..b303904401a3aa6405eaf58777e30273cc0db2b8 --- /dev/null +++ b/Code/Common/otbVectorDataToImageFilter.txx @@ -0,0 +1,720 @@ +/*========================================================================= + + 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 __otbVectorDataToImageFilter_txx +#define __otbVectorDataToImageFilter_txx + +#include <sstream> +#include "otbVectorDataToImageFilter.h" +#include "itkImageRegionIterator.h" +#include "itkImageIteratorWithIndex.h" +#include "otbVectorDataStyle.h" +#include "itkRGBAPixel.h" + +#include <mapnik/datasource_cache.hpp> +#include <mapnik/font_engine_freetype.hpp> +#include <mapnik/agg_renderer.hpp> +#include <mapnik/filter_factory.hpp> +#include <mapnik/color_factory.hpp> +#include <mapnik/image_util.hpp> +#include <mapnik/config_error.hpp> +#include <mapnik/memory_datasource.hpp> +#include <mapnik/layer.hpp> +#include <mapnik/map.hpp> +#include <mapnik/value.hpp> + +#include "ogr_spatialref.h" + +#ifdef OTB_MAPNIK_COMPATIBILITY_API07 +namespace mapnik { +typedef Layer layer; +typedef Image32 image_32; +} +#endif + +namespace otb +{ +namespace mapnik_otb +{ +// this should be removed once mapnik support for version < 2.0 is dropped. +// should be around 01/2013. +#ifdef OTB_MAPNIK_COMPATIBILITY_API07 +static size_t get_num_layer(const mapnik::Map& map) { return map.layerCount(); } +static unsigned get_height(const mapnik::Map& map) { return map.getHeight(); } +static unsigned get_width(const mapnik::Map& map) { return map.getWidth(); } +typedef mapnik::Envelope<double> box2d; +static void zoom_to_box(mapnik::Map* map, const mapnik::Envelope<double>& envelope) +{ + map->zoomToBox(envelope); +} +typedef mapnik::geometry2d geom; +static geom* create_geom(int geom_type) +{ + geom* g = 0; + switch (geom_type) + { + case mapnik::Point: + g = new mapnik::point<mapnik::vertex<double, 2> >; + case mapnik::LineString: + g = new mapnik::line_string<mapnik::vertex<double, 2> , mapnik::vertex_vector2>; + case mapnik::Polygon: + g = new mapnik::polygon<mapnik::vertex<double, 2>, mapnik::vertex_vector2>; + default: + std::cerr + << "Please fix otb::mapnik_otb::create_geom for mapnik 0.7" << std::endl; + } + return g; +} +#else +static size_t get_num_layer(const mapnik::Map& map) { return map.layer_count(); } +static unsigned get_height(const mapnik::Map& map) { return map.height(); } +static unsigned get_width(const mapnik::Map& map) { return map.width(); } +typedef mapnik::box2d<double> box2d; +static void zoom_to_box(mapnik::Map* map, const mapnik::box2d<double>& envelope) +{ + map->zoom_to_box(envelope); +} +typedef mapnik::vertex<double, 2> vertex2d; +typedef mapnik::geometry<vertex2d> geom; +static geom* create_geom(mapnik::eGeomType geom_type) { return new geom(geom_type); } +#endif +} + +/** + * Constructor + */ +template <class TVectorData, class TImage> +VectorDataToImageFilter<TVectorData, TImage> +::VectorDataToImageFilter() : + m_StyleList(), + m_UseAsOverlay(true), + m_RenderingStyleType(OSM) +{ + this->SetNumberOfRequiredInputs(1); + m_Spacing.Fill(1.0); + m_Origin.Fill(0.0); + m_Direction.SetIdentity(); + m_Size.Fill(0); + m_StartIndex.Fill(0); + m_SensorModelFlip = 1; + m_ScaleFactor = 1.0; + m_VectorDataProjectionProj4 = ""; + m_VectorDataProjectionWKT = ""; +} + +template <class TVectorData, class TImage> +void +VectorDataToImageFilter<TVectorData, TImage> +::SetInput(const VectorDataType *input) +{ + // Process object is not const-correct so the const_cast is required here + this->itk::ProcessObject::SetNthInput(0, + const_cast<VectorDataType *>(input)); +} + +template <class TVectorData, class TImage> +void +VectorDataToImageFilter<TVectorData, TImage> +::SetInput(unsigned int idx, const VectorDataType *input) +{ + // Process object is not const-correct so the const_cast is required here + this->itk::ProcessObject::SetNthInput(idx, + const_cast<VectorDataType *>(input)); +} + +template <class TVectorData, class TImage> +const typename VectorDataToImageFilter<TVectorData, TImage>::VectorDataType * +VectorDataToImageFilter<TVectorData, TImage> +::GetInput(void) +{ + if (this->GetNumberOfInputs() < 1) + { + return 0; + } + + return static_cast<const TVectorData *> + (this->itk::ProcessObject::GetInput(0)); +} + +template <class TVectorData, class TImage> +const typename VectorDataToImageFilter<TVectorData, TImage>::VectorDataType * +VectorDataToImageFilter<TVectorData, TImage> +::GetInput(unsigned int idx) +{ + return static_cast<const TVectorData *> + (this->itk::ProcessObject::GetInput(idx)); +} + +//---------------------------------------------------------------------------- +template <class TVectorData, class TImage> +void +VectorDataToImageFilter<TVectorData, TImage> +::SetSpacing(const SpacingType& spacing) +{ + if (this->m_Spacing != spacing) + { + this->m_Spacing = spacing; + this->Modified(); + } +} + +//---------------------------------------------------------------------------- +template <class TVectorData, class TImage> +void +VectorDataToImageFilter<TVectorData, TImage> +::SetSpacing(const double spacing[2]) +{ + SpacingType s(spacing); + this->SetSpacing(s); +} + +//---------------------------------------------------------------------------- +template <class TVectorData, class TImage> +void +VectorDataToImageFilter<TVectorData, TImage> +::SetSpacing(const float spacing[2]) +{ + itk::Vector<float, 2> sf(spacing); + SpacingType s; + s.CastFrom(sf); + this->SetSpacing(s); +} + +//---------------------------------------------------------------------------- +template <class TVectorData, class TImage> +void +VectorDataToImageFilter<TVectorData, TImage> +::SetOrigin(const double origin[2]) +{ + OriginType p(origin); + this->SetOrigin(p); +} + +//---------------------------------------------------------------------------- +template <class TVectorData, class TImage> +void +VectorDataToImageFilter<TVectorData, TImage> +::SetOrigin(const float origin[2]) +{ + itk::Point<float, 2> of(origin); + OriginType p; + p.CastFrom(of); + this->SetOrigin(p); +} + +/** +* Inform pipeline of required output region +*/ +template <class TVectorData, class TImage> +void +VectorDataToImageFilter<TVectorData, TImage> +::GenerateOutputInformation() +{ + // we can't call the superclass method here. + + // get pointers to the input and output + ImagePointer outputPtr = this->GetOutput(); + if (!outputPtr) + { + return; + } + + // Set the size of the output region + typename TImage::RegionType outputLargestPossibleRegion; + outputLargestPossibleRegion.SetSize(m_Size); + outputLargestPossibleRegion.SetIndex(m_StartIndex); + outputPtr->SetLargestPossibleRegion(outputLargestPossibleRegion); + + // Set spacing and origin + outputPtr->SetSpacing(m_Spacing); + outputPtr->SetOrigin(m_Origin); + outputPtr->SetDirection(m_Direction); + + itk::MetaDataDictionary& dict = outputPtr->GetMetaDataDictionary(); + itk::EncapsulateMetaData<std::string> (dict, MetaDataKey::ProjectionRefKey, + static_cast<std::string>(m_VectorDataProjectionWKT)); + + //TODO update or check the projection information + + return; +} + +/** +* BeforeThreadedGenerateData +*/ +template <class TVectorData, class TImage> +void +VectorDataToImageFilter<TVectorData, TImage> +::BeforeThreadedGenerateData(void) +{ + + Superclass::BeforeThreadedGenerateData(); + + //Font Handling + if(!m_FontFileName.empty()) + mapnik::freetype_engine::register_font(m_FontFileName); + + //Handle the style type using helper class + otb::VectorDataStyle::Pointer styleLoader = otb::VectorDataStyle::New(); + styleLoader->SetScaleFactor(m_ScaleFactor); + + //We assume that all the data are reprojected before using OTB. + VectorDataConstPointer input = this->GetInput(); + //Converting the projection string to the proj.4 format + itk::ExposeMetaData<std::string>( + input->GetMetaDataDictionary(), MetaDataKey::ProjectionRefKey, m_VectorDataProjectionWKT); + otbMsgDebugMacro(<< "WKT -> " << m_VectorDataProjectionWKT); + + m_SensorModelFlip = 1; + + if (m_VectorDataProjectionWKT == "") + { + //We assume that it is an image in sensor model geometry + //and tell mapnik that this is utm + //(with a resolution of 1m per unit) + m_VectorDataProjectionProj4 = "+proj=utm +zone=31 +ellps=WGS84"; + m_SensorModelFlip = -1; + otbMsgDevMacro(<< "The output map will be in sensor geometry"); + } + else + { + OGRSpatialReferenceH oSRS = OSRNewSpatialReference(m_VectorDataProjectionWKT.c_str()); + char * pszProj4; + OSRExportToProj4(oSRS, &pszProj4); + m_VectorDataProjectionProj4 = pszProj4; + CPLFree(pszProj4); + OSRRelease(oSRS); + m_SensorModelFlip = 1; + otbMsgDevMacro(<< "The output map will be carto/geo geometry"); + } + otbMsgDebugMacro(<< "Proj.4 -> " << m_VectorDataProjectionProj4); + + //Internal Tiling Support + //Workaround to overcome mapnik maximum tile size limitation + ImagePointer output = this->GetOutput(); + RegionType requestedRegion = output->GetRequestedRegion(); + otbMsgDevMacro("requestedRegion: " << requestedRegion); + + m_NbTile = (vcl_pow(std::max(vcl_floor((double)requestedRegion.GetSize()[0] / 16000), + vcl_floor((double)requestedRegion.GetSize()[1] / 16000))+1, 2)); + + //std::cout << "nbTile: " << m_NbTile << std::endl; + //std::cout << "requestedRegion: " << requestedRegion << std::endl; + + m_TilingRegions.resize(m_NbTile); + m_Maps.resize(m_NbTile); + m_VectorDataExtractors.resize(m_NbTile); + + unsigned int tilingRegionsIdx = 0; + unsigned int stdXOffset; + unsigned int stdYOffset; + + stdXOffset = vcl_floor((double)requestedRegion.GetSize()[0]/ (m_NbTile/2))+1; + stdYOffset = vcl_floor((double)requestedRegion.GetSize()[1]/ (m_NbTile/2))+1; + + for(unsigned int i=0; i < vcl_floor((double)(m_NbTile)/2 + 0.5); ++i) + { + for(unsigned int j=0; j < vcl_floor((double)(m_NbTile)/2 + 0.5); ++j) + { + //Set Regions + SizeType size; + IndexType index; + if(m_NbTile == 1) + { + index = requestedRegion.GetIndex(); + size = requestedRegion.GetSize(); + } + else + { + index[0] = requestedRegion.GetIndex()[0] + i * stdXOffset; + index[1] = requestedRegion.GetIndex()[1] + j * stdYOffset; + + size[0] = std::min((unsigned int)(requestedRegion.GetSize()[0] - index[0]), stdXOffset); + size[1] = std::min((unsigned int)(requestedRegion.GetSize()[1] - index[1]), stdYOffset); + } + m_TilingRegions[tilingRegionsIdx].SetIndex(index); + m_TilingRegions[tilingRegionsIdx].SetSize(size); + + //std::cout << "tileRegions[" << tilingRegionsIdx << "] : " + // << m_TilingRegions[tilingRegionsIdx] << std::endl; + + //Set Maps + m_Maps[tilingRegionsIdx] = mapnik::Map(); + + ////Load the style type + switch (m_RenderingStyleType) + { + case OSM: + { + styleLoader->LoadOSMStyle(m_Maps[tilingRegionsIdx]); + if (m_UseAsOverlay) + { + //Set the default backgroup to transparent + m_Maps[tilingRegionsIdx].set_background(mapnik::color(255, 255, 255, 0)); + } + else + { + m_Maps[tilingRegionsIdx].set_background(mapnik::color("#b5d0d0")); + } + break; + } + case Binary: + { + styleLoader->LoadBinaryRasterizationStyle(m_Maps[tilingRegionsIdx]); + //Set the backgroup to white + m_Maps[tilingRegionsIdx].set_background(mapnik::color("#ffffff")); + break; + } + default: + { + itkExceptionMacro(<< "Style Type Not Supported!"); + break; + } + } + + ////Set Mapnik projection information + m_Maps[tilingRegionsIdx].set_srs(m_VectorDataProjectionProj4); + + //Set VectorData extracts + m_VectorDataExtractors[tilingRegionsIdx].resize(this->GetNumberOfInputs()); + for (unsigned int idx = 0; idx < this->GetNumberOfInputs(); ++idx) + { + if (this->GetInput(idx)) + { + RemoteSensingRegionType rsRegion; + SizePhyType sizePhy; + sizePhy[0] = size[0] * m_Spacing[0]; + sizePhy[1] = size[1] * m_Spacing[1]; + rsRegion.SetSize(sizePhy); + OriginType origin; + origin[0] = m_Origin[0] + index[0] * m_Spacing[0]; + origin[1] = m_Origin[1] + index[1] * m_Spacing[1]; + rsRegion.SetOrigin(origin); + rsRegion.SetRegionProjection(m_VectorDataProjectionWKT); + + //std::cout << "m_SensorModelFlip: " << m_SensorModelFlip << std::endl; + //std::cout << "rsTileRegions[" << tilingRegionsIdx << "] : " + // << rsRegion << std::endl; + + m_VectorDataExtractors[tilingRegionsIdx][idx] = VectorDataExtractROIType::New(); + m_VectorDataExtractors[tilingRegionsIdx][idx]->SetRegion(rsRegion); + m_VectorDataExtractors[tilingRegionsIdx][idx]->SetInput(this->GetInput(idx)); + } + } + + tilingRegionsIdx ++; + } + } +} + +/** + * Generate Data + */ +template <class TVectorData, class TImage> +void +VectorDataToImageFilter<TVectorData, TImage> +::GenerateData(void) +{ + + this->AllocateOutputs(); + + this->BeforeThreadedGenerateData(); + + if (m_StyleList.size() == 0) + { + switch (m_RenderingStyleType) + { + case OSM: + { + //Add default styles + itkExceptionMacro(<< "No style is provided for the vector data"); + break; + } + case Binary: + { + //Add default styles + this->AddStyle("binary-rasterization"); + break; + } + default: + { + itkExceptionMacro(<< "No style is provided for the vector data"); + break; + } + } + } + + ImagePointer output = this->GetOutput(); + + for (unsigned int tileIdx = 0; tileIdx < m_NbTile; ++tileIdx) + { + //Delete the previous layers from the map + int numberLayer = mapnik_otb::get_num_layer(m_Maps[tileIdx]); + for (int i = numberLayer - 1; i >= 0; i--) //yes, int. + { + m_Maps[tileIdx].removeLayer(i); + } + m_Maps[tileIdx].resize(m_TilingRegions[tileIdx].GetSize()[0], m_TilingRegions[tileIdx].GetSize()[1]); + + for (unsigned int vdIdx = 0; vdIdx < this->GetNumberOfInputs(); ++vdIdx) + { + if (this->GetInput(vdIdx)) + { + datasource_ptr mDatasource = datasource_ptr(new mapnik::memory_datasource); + + m_VectorDataExtractors[tileIdx][vdIdx]->Update(); + VectorDataConstPointer input = m_VectorDataExtractors[tileIdx][vdIdx]->GetOutput(); + InternalTreeNodeType * inputRoot = const_cast<InternalTreeNodeType *>(input->GetDataTree()->GetRoot()); + + ProcessNode(inputRoot, mDatasource); + otbMsgDevMacro("Datasource size: " << mDatasource->size()); + + std::stringstream layerName; + layerName << "layer-" << tileIdx; + mapnik::layer lyr(layerName.str()); + lyr.set_srs(m_VectorDataProjectionProj4); + lyr.set_datasource(mDatasource); + + for (unsigned int i = 0; i < m_StyleList.size(); ++i) + { + lyr.add_style(m_StyleList[i]); + } + + m_Maps[tileIdx].addLayer(lyr); + } + } + assert((m_SensorModelFlip == 1) || (m_SensorModelFlip == -1)); + + mapnik_otb::box2d envelope( + m_Origin[0] + m_TilingRegions[tileIdx].GetIndex()[0]*m_Spacing[0], + m_SensorModelFlip*(m_Origin[1] + m_TilingRegions[tileIdx].GetIndex()[1] * m_Spacing[1] + + m_TilingRegions[tileIdx].GetSize()[1] * m_Spacing[1]), + m_Origin[0] + m_TilingRegions[tileIdx].GetIndex()[0] * m_Spacing[0] + + m_TilingRegions[tileIdx].GetSize()[0] * m_Spacing[0], + m_SensorModelFlip*(m_Origin[1] + m_TilingRegions[tileIdx].GetIndex()[1] * m_Spacing[1]) + ); + + mapnik_otb::zoom_to_box(&m_Maps[tileIdx], envelope); + otbMsgDebugMacro(<< "Envelope: " << envelope); + + otbMsgDebugMacro(<< "Map scale: " << m_Maps[tileIdx].scale_denominator()); + mapnik::image_32 buf(mapnik_otb::get_width(m_Maps[tileIdx]), + mapnik_otb::get_height(m_Maps[tileIdx])); + mapnik::agg_renderer<mapnik::image_32> ren(m_Maps[tileIdx], buf); + ren.apply(); + + const unsigned char * src = buf.raw_data(); + + itk::ImageRegionIterator<ImageType> it(output, m_TilingRegions[tileIdx]); + + for (it.GoToBegin(); !it.IsAtEnd(); ++it) + { + itk::RGBAPixel<unsigned char> pix; + pix[0] = *src; + pix[1] = *(src+1); + pix[2] = *(src+2); + pix[3] = *(src+3); + src += 4; + + it.Set(m_RGBAConverter->Convert(pix)); + } + } +} + +template <class TVectorData, class TImage> +void +VectorDataToImageFilter<TVectorData, TImage> +::ProcessNode(InternalTreeNodeType * source, datasource_ptr mDatasource) +{ + typedef typename VectorDataType::DataNodeType DataNodeType; + typedef typename DataNodeType::Pointer DataNodePointerType; + + // Get the children list from the input node + ChildrenListType children = source->GetChildrenList(); + + // For each child + for (typename ChildrenListType::iterator it = children.begin(); it != children.end(); ++it) + { + // Copy input DataNode info + DataNodePointerType dataNode = (*it)->Get(); + + switch (dataNode->GetNodeType()) + { + case otb::ROOT: + { + ProcessNode((*it), mDatasource); + break; + } + case otb::DOCUMENT: + { + ProcessNode((*it), mDatasource); + break; + } + case otb::FOLDER: + { + ProcessNode((*it), mDatasource); + break; + } + case FEATURE_POINT: + { + mapnik_otb::geom* point = mapnik_otb::create_geom(mapnik::Point); + + point->move_to(dataNode->GetPoint()[0], m_SensorModelFlip * dataNode->GetPoint()[1]); +// std::cout << dataNode->GetPoint()[0] << ", " << dataNode->GetPoint()[1] << std::endl; + + typedef boost::shared_ptr<mapnik::raster> raster_ptr; + typedef mapnik::feature<mapnik_otb::geom, raster_ptr> Feature; + typedef boost::shared_ptr<Feature> feature_ptr; + + feature_ptr mfeature = feature_ptr(new Feature(1)); + mfeature->add_geometry(point); + + mapnik::transcoder tr("ISO-8859-15"); + + if (dataNode->HasField("place_name")) + boost::put(*mfeature, "name", + tr.transcode((dataNode->GetFieldAsString("place_name")).c_str())); + + boost::put(*mfeature, "place", tr.transcode("city")); + boost::put(*mfeature, "capital", tr.transcode("yes")); //FIXME more a question of style + + boost::put(*mfeature, "geometry", tr.transcode("point")); + + mDatasource->push(mfeature); + + break; + } + case otb::FEATURE_LINE: + { + mapnik_otb::geom* line = mapnik_otb::create_geom(mapnik::LineString); + + typedef typename DataNodeType::LineType::VertexListConstIteratorType VertexIterator; + VertexIterator itVertex = dataNode->GetLine()->GetVertexList()->Begin(); + while (itVertex != dataNode->GetLine()->GetVertexList()->End()) + { +// std::cout << itVertex.Value()[0] << ", " << itVertex.Value()[1] << std::endl; + line->line_to(itVertex.Value()[0], m_SensorModelFlip * itVertex.Value()[1]); + ++itVertex; + } + +// std::cout << "Num points: " << line->num_points() << std::endl; + + typedef boost::shared_ptr<mapnik::raster> raster_ptr; + typedef mapnik::feature<mapnik_otb::geom, raster_ptr> Feature; + typedef boost::shared_ptr<Feature> feature_ptr; + + feature_ptr mfeature = feature_ptr(new Feature(1)); + mfeature->add_geometry(line); + + mapnik::transcoder tr("ISO-8859-15"); + + if (dataNode->HasField("name")) + boost::put(*mfeature, "name", + tr.transcode((dataNode->GetFieldAsString("name")).c_str())); + if (dataNode->HasField("NAME")) + boost::put(*mfeature, "name", + tr.transcode((dataNode->GetFieldAsString("NAME")).c_str())); + +// std::cout << mfeature->props().size() << std::endl; +// std::cout << " -> " << (*mfeature)["name"] << std::endl; + +// std::cout << "Name: " << dataNode->GetFieldAsString("NAME") << std::endl; +// std::cout << "Type: " << dataNode->GetFieldAsString("TYPE") << std::endl; +// std::cout << "OSM ID: " << dataNode->GetFieldAsString("osm_id") << std::endl; + + if (dataNode->HasField("type")) + boost::put(*mfeature, "highway", + tr.transcode((dataNode->GetFieldAsString("type")).c_str())); + if (dataNode->HasField("TYPE")) + boost::put(*mfeature, "highway", + tr.transcode((dataNode->GetFieldAsString("TYPE")).c_str())); + + boost::put(*mfeature, "geometry", tr.transcode("line")); + + mDatasource->push(mfeature); + + break; + } + case FEATURE_POLYGON: + { + mapnik_otb::geom* polygon = mapnik_otb::create_geom(mapnik::Polygon); + + typedef typename DataNodeType::PolygonType::VertexListConstIteratorType VertexIterator; + VertexIterator itVertex = dataNode->GetPolygonExteriorRing()->GetVertexList()->Begin(); + while (itVertex != dataNode->GetPolygonExteriorRing()->GetVertexList()->End()) + { + polygon->line_to(itVertex.Value()[0], m_SensorModelFlip * itVertex.Value()[1]); + ++itVertex; + } + + typedef boost::shared_ptr<mapnik::raster> raster_ptr; + typedef mapnik::feature<mapnik_otb::geom, raster_ptr> Feature; + typedef boost::shared_ptr<Feature> feature_ptr; + + feature_ptr mfeature = feature_ptr(new Feature(1)); + mfeature->add_geometry(polygon); + + mapnik::transcoder tr("ISO-8859-15"); + + boost::put(*mfeature, "geometry", tr.transcode("polygon")); + + mDatasource->push(mfeature); + + break; + } + case FEATURE_MULTIPOINT: + { + itkExceptionMacro( + << "This type (FEATURE_MULTIPOINT) is not handle (yet) by VectorDataToImageFilter(), please request for it"); + break; + } + case FEATURE_MULTILINE: + { + itkExceptionMacro( + << "This type (FEATURE_MULTILINE) is not handle (yet) by VectorDataToImageFilter(), please request for it"); + break; + } + case FEATURE_MULTIPOLYGON: + { + itkExceptionMacro( + << "This type (FEATURE_MULTIPOLYGON) is not handle (yet) by VectorDataToImageFilter(), please request for it"); + break; + } + case FEATURE_COLLECTION: + { + itkExceptionMacro( + << "This type (FEATURE_COLLECTION) is not handle (yet) by VectorDataToImageFilter(), please request for it"); + break; + } + } + } +} + +/** + * PrintSelf Method + */ +template <class TVectorData, class TImage> +void +VectorDataToImageFilter<TVectorData, TImage> +::PrintSelf(std::ostream& os, itk::Indent indent) const +{ + Superclass::PrintSelf(os, indent); +} +} + +#endif diff --git a/Testing/Code/Common/CMakeLists.txt b/Testing/Code/Common/CMakeLists.txt index d3a2ee6ea2be8a57eca21d5e9fe4fdb50731b21f..096b1f56015f89edaaa36aba7dddcb41e0b73550 100644 --- a/Testing/Code/Common/CMakeLists.txt +++ b/Testing/Code/Common/CMakeLists.txt @@ -871,6 +871,29 @@ ADD_TEST(coTvVectorDataToMapFilterNoFonts ${COMMON_TESTS9} ${TEMP}/coTvVectorDataToMapFilterNoFonts.png ) + +# Deprecated class +ADD_TEST(coTvVectorDataToImageFilter ${COMMON_TESTS9} + --compare-image ${NOTOL} + ${BASELINE}/coTvVectorDataToMapFilter.png + ${TEMP}/coTvVectorDataToImageFilter.png + otbVectorDataToImageFilter + ${LARGEINPUT}/VECTOR/MidiPyrenees/roads.shp + ${TEMP}/coTvVectorDataToImageFilter.png + ${INPUTDATA}/DejaVuSans.ttf # font +) + +ADD_TEST(coTvVectorDataToImageFilterBinary ${COMMON_TESTS9} + --compare-image ${NOTOL} + ${BASELINE}/coTvVectorDataToMapFilterBinary.png + ${TEMP}/coTvVectorDataToImageFilterBinary.png + otbVectorDataToImageFilterBinary + ${LARGEINPUT}/VECTOR/MidiPyrenees/roads.shp + ${TEMP}/coTvVectorDataToImageFilterBinary.png +) + + + ENDIF(OTB_DATA_USE_LARGEINPUT) @@ -1358,7 +1381,7 @@ otbVectorDataToMapFilter.cxx otbVectorDataToMapFilterSensorModel.cxx otbVectorDataToMapFilterWorld.cxx otbVectorDataToMapFilterNoFonts.cxx - +otbVectorDataToImageFilter.cxx ) ENDIF(OTB_USE_MAPNIK) diff --git a/Testing/Code/Common/otbCommonTests9.cxx b/Testing/Code/Common/otbCommonTests9.cxx index 21d5d1ff82684dfff76c77ccac8c4ca840475ff0..3f2f7455510a55f6bdd1b4eda670f6c073971d52 100644 --- a/Testing/Code/Common/otbCommonTests9.cxx +++ b/Testing/Code/Common/otbCommonTests9.cxx @@ -30,4 +30,8 @@ void RegisterTests() REGISTER_TEST(otbVectorDataToMapFilterSensorModel); REGISTER_TEST(otbVectorDataToMapFilterWorld); REGISTER_TEST(otbVectorDataToMapFilterNoFonts); + + // Deprecated + REGISTER_TEST(otbVectorDataToImageFilter); + REGISTER_TEST(otbVectorDataToImageFilterBinary); } diff --git a/Testing/Code/Common/otbVectorDataToImageFilter.cxx b/Testing/Code/Common/otbVectorDataToImageFilter.cxx new file mode 100644 index 0000000000000000000000000000000000000000..100a03eece5929661c071c31bdf194f69774b235 --- /dev/null +++ b/Testing/Code/Common/otbVectorDataToImageFilter.cxx @@ -0,0 +1,183 @@ +/*========================================================================= + + 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. + +=========================================================================*/ + +#include "otbVectorDataFileReader.h" +#include "otbImageFileWriter.h" +#include "otbVectorData.h" +#include "otbVectorDataProjectionFilter.h" +#include "otbVectorDataExtractROI.h" +#include <fstream> +#include <iostream> + +#include "itkRGBAPixel.h" +#include "otbImage.h" +#include "otbVectorDataToImageFilter.h" + +int otbVectorDataToImageFilter(int argc, char * argv[]) +{ + + if (argc < 4) + { + std::cout << argv[0] << " <input vector filename> <input image filename> <font filename>" << std::endl; + + return EXIT_FAILURE; + } + + //Read the vector data + typedef otb::VectorData<> VectorDataType; + typedef otb::VectorDataFileReader<VectorDataType> VectorDataFileReaderType; + VectorDataFileReaderType::Pointer reader = VectorDataFileReaderType::New(); + + reader->SetFileName(argv[1]); + + //Reproject the vector data in the proper projection + typedef otb::VectorDataProjectionFilter<VectorDataType, VectorDataType> ProjectionFilterType; + ProjectionFilterType::Pointer projection = ProjectionFilterType::New(); + projection->SetInput(reader->GetOutput()); + + std::string projectionRefWkt = + "PROJCS[\"UTM Zone 31, Northern Hemisphere\", GEOGCS[\"WGS 84\", DATUM[\"WGS_1984\", SPHEROID[\"WGS 84\", 6378137, 298.257223563, AUTHORITY[\"EPSG\",\"7030\"]], TOWGS84[0, 0, 0, 0, 0, 0, 0], AUTHORITY[\"EPSG\",\"6326\"]], PRIMEM[\"Greenwich\", 0, AUTHORITY[\"EPSG\",\"8901\"]], UNIT[\"degree\", 0.0174532925199433, AUTHORITY[\"EPSG\",\"9108\"]], AXIS[\"Lat\", NORTH], AXIS[\"Long\", EAST], AUTHORITY[\"EPSG\",\"4326\"]], PROJECTION[\"Transverse_Mercator\"], PARAMETER[\"latitude_of_origin\", 0], PARAMETER[\"central_meridian\", 3], PARAMETER[\"scale_factor\", 0.9996], PARAMETER[\"false_easting\", 500000], PARAMETER[\"false_northing\", 0], UNIT[\"Meter\", 1]]"; + + projection->SetOutputProjectionRef(projectionRefWkt); + + //Convert the vector data into an image + typedef itk::RGBAPixel<unsigned char> PixelType; + typedef otb::Image<PixelType, 2> ImageType; + + ImageType::SizeType size; + size[0] = 500; + size[1] = 500; + + ImageType::PointType origin; + origin[0] = 374149.980555821; //UL easting + origin[1] = 4829183.99443839; //UL northing + + ImageType::SpacingType spacing; + spacing[0] = 0.6; + spacing[1] = -0.6; + + typedef otb::RemoteSensingRegion<double> RegionType; + RegionType region; + RegionType::SizeType sizeInUnit; + sizeInUnit[0] = size[0] * spacing[0]; + sizeInUnit[1] = size[1] * spacing[1]; + region.SetSize(sizeInUnit); + region.SetOrigin(origin); + region.SetRegionProjection(projectionRefWkt); + + typedef otb::VectorDataExtractROI<VectorDataType> ExtractROIType; + ExtractROIType::Pointer extractROI = ExtractROIType::New(); + extractROI->SetRegion(region); + extractROI->SetInput(projection->GetOutput()); + + typedef otb::VectorDataToImageFilter<VectorDataType, ImageType> VectorDataToImageFilterType; + VectorDataToImageFilterType::Pointer vectorDataRendering = VectorDataToImageFilterType::New(); + vectorDataRendering->SetInput(extractROI->GetOutput()); + + vectorDataRendering->SetSize(size); + vectorDataRendering->SetOrigin(origin); + vectorDataRendering->SetSpacing(spacing); + vectorDataRendering->SetFontFileName(argv[3]); + vectorDataRendering->AddStyle("minor-roads-casing"); + vectorDataRendering->AddStyle("roads-text"); + + //Save the image in a file + typedef otb::ImageFileWriter<ImageType> WriterType; + WriterType::Pointer writer = WriterType::New(); + writer->SetInput(vectorDataRendering->GetOutput()); + writer->SetFileName(argv[2]); + writer->Update(); + + return EXIT_SUCCESS; +} + +int otbVectorDataToImageFilterBinary(int argc, char * argv[]) +{ + + if (argc < 3) + { + std::cout << argv[0] << " <input vector filename> <input image filename>" << std::endl; + + return EXIT_FAILURE; + } + + //Read the vector data + typedef otb::VectorData<> VectorDataType; + typedef otb::VectorDataFileReader<VectorDataType> VectorDataFileReaderType; + VectorDataFileReaderType::Pointer reader = VectorDataFileReaderType::New(); + + reader->SetFileName(argv[1]); + + //Reproject the vector data in the proper projection + typedef otb::VectorDataProjectionFilter<VectorDataType, VectorDataType> ProjectionFilterType; + ProjectionFilterType::Pointer projection = ProjectionFilterType::New(); + projection->SetInput(reader->GetOutput()); + + std::string projectionRefWkt = + "PROJCS[\"UTM Zone 31, Northern Hemisphere\", GEOGCS[\"WGS 84\", DATUM[\"WGS_1984\", SPHEROID[\"WGS 84\", 6378137, 298.257223563, AUTHORITY[\"EPSG\",\"7030\"]], TOWGS84[0, 0, 0, 0, 0, 0, 0], AUTHORITY[\"EPSG\",\"6326\"]], PRIMEM[\"Greenwich\", 0, AUTHORITY[\"EPSG\",\"8901\"]], UNIT[\"degree\", 0.0174532925199433, AUTHORITY[\"EPSG\",\"9108\"]], AXIS[\"Lat\", NORTH], AXIS[\"Long\", EAST], AUTHORITY[\"EPSG\",\"4326\"]], PROJECTION[\"Transverse_Mercator\"], PARAMETER[\"latitude_of_origin\", 0], PARAMETER[\"central_meridian\", 3], PARAMETER[\"scale_factor\", 0.9996], PARAMETER[\"false_easting\", 500000], PARAMETER[\"false_northing\", 0], UNIT[\"Meter\", 1]]"; + + projection->SetOutputProjectionRef(projectionRefWkt); + + //Convert the vector data into an image + typedef itk::RGBAPixel<unsigned char> PixelType; + typedef otb::Image<PixelType, 2> ImageType; + + ImageType::SizeType size; + size[0] = 500; + size[1] = 500; + + ImageType::PointType origin; + origin[0] = 374149.980555821; //UL easting + origin[1] = 4829183.99443839; //UL northing + + ImageType::SpacingType spacing; + spacing[0] = 0.6; + spacing[1] = -0.6; + + typedef otb::RemoteSensingRegion<double> RegionType; + RegionType region; + RegionType::SizeType sizeInUnit; + sizeInUnit[0] = size[0] * spacing[0]; + sizeInUnit[1] = size[1] * spacing[1]; + region.SetSize(sizeInUnit); + region.SetOrigin(origin); + region.SetRegionProjection(projectionRefWkt); + + typedef otb::VectorDataExtractROI<VectorDataType> ExtractROIType; + ExtractROIType::Pointer extractROI = ExtractROIType::New(); + extractROI->SetRegion(region); + extractROI->SetInput(projection->GetOutput()); + + typedef otb::VectorDataToImageFilter<VectorDataType, ImageType> VectorDataToImageFilterType; + VectorDataToImageFilterType::Pointer vectorDataRendering = VectorDataToImageFilterType::New(); + vectorDataRendering->SetInput(extractROI->GetOutput()); + + vectorDataRendering->SetSize(size); + vectorDataRendering->SetOrigin(origin); + vectorDataRendering->SetSpacing(spacing); + vectorDataRendering->SetRenderingStyleType(VectorDataToImageFilterType::Binary); + + //Save the image in a file + typedef otb::ImageFileWriter<ImageType> WriterType; + WriterType::Pointer writer = WriterType::New(); + writer->SetInput(vectorDataRendering->GetOutput()); + writer->SetFileName(argv[2]); + writer->Update(); + + return EXIT_SUCCESS; +}