From f2fee9c78aea503695a5a38f569e75c4943526df Mon Sep 17 00:00:00 2001 From: Otmane Lahlou <otmane.lahlou@c-s.fr> Date: Mon, 6 Dec 2010 18:44:42 +0100 Subject: [PATCH] ADD : kmz writer class, tests and example --- Code/IO/otbKmzProductWriter.h | 272 +++++ Code/IO/otbKmzProductWriter.txx | 1281 +++++++++++++++++++++++ Examples/IO/CMakeLists.txt | 41 + Examples/IO/ImageToKmzChain.cxx | 162 +++ Examples/IO/otbIOExamplesTests1.cxx | 6 + Testing/Code/IO/CMakeLists.txt | 36 + Testing/Code/IO/otbIOTests21.cxx | 2 + Testing/Code/IO/otbKmzProductWriter.cxx | 95 ++ 8 files changed, 1895 insertions(+) create mode 100644 Code/IO/otbKmzProductWriter.h create mode 100644 Code/IO/otbKmzProductWriter.txx create mode 100644 Examples/IO/ImageToKmzChain.cxx create mode 100644 Testing/Code/IO/otbKmzProductWriter.cxx diff --git a/Code/IO/otbKmzProductWriter.h b/Code/IO/otbKmzProductWriter.h new file mode 100644 index 0000000000..f3715adea6 --- /dev/null +++ b/Code/IO/otbKmzProductWriter.h @@ -0,0 +1,272 @@ +/*========================================================================= + + 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 __otbKmzProductWriter_h +#define __otbKmzProductWriter_h + +#include "itkProcessObject.h" +#include "itkObjectFactory.h" + +//kmz creation +#include "kml/engine/kmz_file.h" +#include "kml/base/file.h" + +// Image Tiling +#include "otbMultiChannelExtractROI.h" +#include "otbImageFileWriter.h" +#include "otbVectorRescaleIntensityImageFilter.h" +#include <ogr_spatialref.h> +#include "otbGenericRSTransform.h" +#include "otbStreamingShrinkImageFilter.h" +#include "itkCastImageFilter.h" + +// Possiblity to includes vectordatas necessary includes +#include "otbVectorData.h" +#include "otbVectorDataFileWriter.h" + + +namespace otb +{ + +/** \class KmzProductWriter + * \brief This class generate a Kmz from one or several input + * images. The inputs must have a non empty metadata informations. + * + * This class writes kmz files, supported by GE. The input must have + * metadata + * The size of the tiles can be set via the method + * SetTileSize(unsigned int) + * + * + * \ingroup IO + * + */ +template <class TInputImage> +class ITK_EXPORT KmzProductWriter : public itk::ProcessObject +{ +public: + /** Standard class typedefs. */ + typedef KmzProductWriter Self; + typedef itk::ProcessObject 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(KmzProductWriter, itk::ProcessObject); + + /** Some convenient typedefs. */ + typedef TInputImage InputImageType; + typedef typename InputImageType::InternalPixelType InternalPixelType; + typedef typename InputImageType::SizeType SizeType; + typedef typename InputImageType::IndexType IndexType; + typedef unsigned char OutputPixelType; + typedef typename InputImageType::Pointer InputImagePointer; + typedef typename InputImageType::RegionType InputImageRegionType; + typedef typename InputImageType::PixelType InputImagePixelType; + + typedef VectorData<double,2> VectorDataType; + typedef typename VectorDataType::DataNodeType DataNodeType; + typedef typename DataNodeType::PolygonType PolygonType; + typedef typename PolygonType::VertexType VertexType; + + typedef VectorDataFileWriter<VectorDataType> VectorDataFileWriterType; + + + /// Multi channels Extract ROI filter + typedef MultiChannelExtractROI<InternalPixelType, OutputPixelType> VectorImageExtractROIFilterType; + + // Writer + typedef ImageFileWriter< VectorImage<OutputPixelType> > VectorWriterType; + + // Resampler + typedef StreamingShrinkImageFilter<InputImageType,InputImageType > StreamingShrinkImageFilterType; + + // Intensity Rescale + typedef VectorRescaleIntensityImageFilter<InputImageType, + InputImageType> VectorRescaleIntensityImageFilterType; + + // Transformer + typedef GenericRSTransform<> TransformType; + typedef TransformType::InputPointType InputPointType; + typedef TransformType::OutputPointType OutputPointType; + + // Cast Image Filter + typedef itk::CastImageFilter<InputImageType, VectorImage<OutputPixelType> > CastFilterType; + + + /** Dimension of input image. */ + itkStaticConstMacro(InputImageDimension, unsigned int, + InputImageType::ImageDimension); + + virtual void SetInput( const InputImageType *image); + virtual void SetInput( unsigned int, const TInputImage * image); + const InputImageType * GetInput(void); + const InputImageType * GetInput(unsigned int idx); + + itkSetStringMacro(Path); + + /** Update Method */ + virtual void Update() + { + this->Write(); + } + +protected: + KmzProductWriter(); + virtual ~KmzProductWriter(); + void PrintSelf(std::ostream& os, itk::Indent indent) const; + + /**Method for Tiling the input image*/ + virtual void Tiling(); + + /** Method for writing */ + virtual void Write(); + +private: + KmzProductWriter(const Self &); //purposely not implemented + void operator =(const Self&); //purposely not implemented + + /** Mehtod to initialize the variables*/ + virtual void Initialize(); + + /** + * Close the root kml by adding the last flags and close the + * std::ofstream + */ + void CloseRootKML(); + +// /** Method to avoid code duplication*/ +// /** call the method that generates the bounding box kml*/ +// void BoundingBoxKmlProcess(double north, double south, double east, double west); + + /** Method to generate the root kml*/ + void RootKmlProcess(double north, double south, double east, double west); + +// /** Add Roi to kmz*/ +// void RegionOfInterestProcess(); + + /** KML root generate */ + void GenerateKMLRoot(std::string title, double north, double south, double east, double west, bool extended); + + /** KML generate Filename - PathName - tile number - North - South - East - West */ + void GenerateKML(std::string pathname, int depth, int x, int y, double north, double south, double east, double west); + void GenerateKMLExtended(std::string pathname, + int depth, + int x, + int y, + OutputPointType lowerLeft, + OutputPointType lowerRight, + OutputPointType upperRight, + OutputPointType upperLeft); + + /** KML with link generate */ + void GenerateKMLWithLink(std::string pathname, + int depth, int x, int y, int tileStartX, int tileStartY, + double north, double south, double east, double west, double centerLong, double centerLat); + void GenerateKMLExtendedWithLink(std::string pathname, + int depth, int x, int y, int tileStartX, int tileStartY, + OutputPointType lowerLeft, OutputPointType lowerRight, + OutputPointType upperRight, OutputPointType upperLeft, + double centerLong, double centerLat); + +// /** Method to create the bounding kml of the "iteration" th product */ +// void GenerateBoundingKML(double north, double south, +// double east, double west); + + + /** + * Add a networkLink <NetworkLink> .... </NetworkLink> + * to root kml (used to handle several image in the same kmz) + */ + void AddNetworkLinkToRootKML(double north, + double south, + double east, + double west, + std::string directory, + bool addRegion, + unsigned int pos); + + /** + * Add file to KMZ : return the number of error when writing the + * file in the kmz + */ + virtual int AddFileToKMZ(std::ostringstream& absolutePath, std::ostringstream& kmz_in_path); + + /**Cut the image file name to built the directory name*/ + std::string GetCuttenFileName(std::string description, unsigned int idx); + + std::string m_Path; + bool m_UseExtendMode; + InputImagePointer m_VectorImage; + InputImagePointer m_ResampleVectorImage; + + // Extract ROI + typename VectorImageExtractROIFilterType::Pointer m_VectorImageExtractROIFilter; + + // Writer + typename VectorWriterType::Pointer m_VectorWriter; + + // Resampler + typename StreamingShrinkImageFilterType::Pointer m_StreamingShrinkImageFilter; + + // Rescale intensity + typename VectorRescaleIntensityImageFilterType::Pointer m_VectorRescaleIntensityImageFilter; + + // Transformer + typename TransformType::Pointer m_Transform; + + // VectorData Pointer Type for tileindex shapefile + typename VectorDataType::Pointer m_VectorDataIndexTile; + typename DataNodeType::Pointer m_Polygon; + typename DataNodeType::Pointer m_MultiPolygon; + typename DataNodeType::Pointer m_Folder; + + // Tile size + int m_TileSize; + int m_MaxDepth; + int m_CurrentDepth; + unsigned int m_CurIdx; + + // KMZ file + kmlengine::KmzFilePtr m_KmzFile; + + // KMZ file name + std::ostringstream m_KmzFileName; + + // the kml root ofstream + std::ofstream m_RootKmlFile; + std::ofstream m_TempRootKmlFile; + + // File and path name + std::string m_FileName; + std::string m_CurrentImageName; + + // Convenience string + std::string m_KmzExtension; + std::string m_KmlExtension; +}; + +} // end namespace otb + +#ifndef OTB_MANUAL_INSTANTIATION +#include "otbKmzProductWriter.txx" +#endif + +#endif diff --git a/Code/IO/otbKmzProductWriter.txx b/Code/IO/otbKmzProductWriter.txx new file mode 100644 index 0000000000..0f730119a9 --- /dev/null +++ b/Code/IO/otbKmzProductWriter.txx @@ -0,0 +1,1281 @@ +/*========================================================================= + + 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 __otbKmzProductWriter_txx +#define __otbKmzProductWriter_txx + +#include "otbKmzProductWriter.h" +#include "itksys/SystemTools.hxx" + +#include "otbMetaDataKey.h" +#include "otbVectorDataKeywordlist.h" +#include "string.h" + +namespace otb +{ +template <class TInputImage> +KmzProductWriter<TInputImage> +::KmzProductWriter(): m_TileSize(512),m_UseExtendMode(true) +{ + // Modify superclass default values, can be overridden by subclasses + this->SetNumberOfRequiredInputs(1); +} + +template <class TInputImage> +KmzProductWriter<TInputImage> +::~KmzProductWriter() +{ + // Reset the boost::intrusive_ptr<KmzFile> : + // TODO : when upgrading boost > 1.42 use method release(). + m_KmzFile = NULL; +} + +/** + * + */ +template <class TInputImage> +void +KmzProductWriter<TInputImage> +::SetInput(const InputImageType *input) +{ + // Process object is not const-correct so the const_cast is required here + this->ProcessObject::SetNthInput(0, + const_cast< InputImageType * >( input ) ); +} + + +template <class TInputImage> +void +KmzProductWriter<TInputImage> +::SetInput( unsigned int index, const TInputImage * image ) +{ + // Process object is not const-correct so the const_cast is required here + this->ProcessObject::SetNthInput(index, + const_cast< TInputImage *>( image ) ); +} + +/** + * + */ +template <class TInputImage> +const typename KmzProductWriter<TInputImage>::InputImageType * +KmzProductWriter<TInputImage> +::GetInput(void) +{ + if (this->GetNumberOfInputs() < 1) + { + return 0; + } + + return static_cast<const TInputImage * > + (this->ProcessObject::GetInput(0) ); +} + +/** + * + */ +template <class TInputImage> +const typename KmzProductWriter<TInputImage>::InputImageType * +KmzProductWriter<TInputImage> +::GetInput(unsigned int idx) +{ + return static_cast< const TInputImage * > + (this->ProcessObject::GetInput(idx)); +} + +template <class TInputImage> +void +KmzProductWriter<TInputImage> +::Write() +{ + m_VectorImage = const_cast<TInputImage *>(this->GetInput()); + std::cout <<"Input Information " << m_VectorImage->GetLargestPossibleRegion() << std::endl; + this->Initialize(); + this->Tiling(); +} + + +template <class TInputImage> +void +KmzProductWriter<TInputImage> +::Initialize() +{ + m_FileName = itksys::SystemTools::GetFilenameWithoutExtension(m_Path); + m_Path = itksys::SystemTools::GetFilenamePath(m_Path); + m_CurrentImageName = this->GetCuttenFileName(m_FileName, 0); + + // Create the extension following the user choice + if (m_UseExtendMode) + { + m_KmzExtension = "xt.kmz"; + m_KmlExtension = "xt.kml"; + } + else + { + m_KmzExtension = ".kmz"; + m_KmlExtension = ".kml"; + } + + // Create a kmz file + m_KmzFileName << m_Path << "/" << m_FileName << m_KmzExtension; + m_KmzFile = kmlengine::KmzFile::Create(m_KmzFileName.str().c_str()); +} + + +template <class TInputImage> +void +KmzProductWriter<TInputImage> +::Tiling() +{ + unsigned int numberOfChannel = m_VectorImage->GetNumberOfComponentsPerPixel(); + unsigned int curIdx = 0; + + /** Image statistics*/ + typename InputImageType::PixelType inMin(numberOfChannel), inMax(numberOfChannel), outMin(numberOfChannel), outMax( + numberOfChannel); + outMin.Fill(0); + outMax.Fill(255); + + // Build wgs ref to compute long/lat + OGRSpatialReference oSRS; + oSRS.SetWellKnownGeogCS("WGS84"); + char * wgsRef = NULL; + oSRS.exportToWkt(&wgsRef); + + // Update image base information + m_VectorImage->UpdateOutputInformation(); + + // Get the image size + SizeType size; + size = m_VectorImage->GetLargestPossibleRegion().GetSize(); + + int sizeX = size[0]; + int sizeY = size[1]; + + // Compute max depth + int maxDepth = + static_cast<int>(max(vcl_ceil(vcl_log(static_cast<float>(sizeX) / static_cast<float>(m_TileSize)) / vcl_log(2.0)), + vcl_ceil(vcl_log(static_cast<float>(sizeY) / static_cast<float>(m_TileSize)) / vcl_log(2.0)))); + m_MaxDepth = maxDepth; + m_CurIdx = 0; + + // Compute nbTile + int nbTile = 0; + + for (int i = 0; i <= maxDepth; i++) + { + int ratio = static_cast<int>(vcl_pow(2., (maxDepth - i))); + nbTile += (((sizeX / ratio) / m_TileSize) + 1) * (((sizeY / ratio) / m_TileSize) + 1); + } + + // Extract size & index + SizeType extractSize; + IndexType extractIndex; + + std::cout << "maxDepth " << maxDepth<< std::endl; + for (int depth = 0; depth <= maxDepth; depth++) + { + + // update the attribute value Current Depth + m_CurrentDepth = depth; + + // Resample image to the max Depth + int sampleRatioValue = static_cast<int>(vcl_pow(2., (maxDepth - depth))); + + if (sampleRatioValue > 1) + { + m_StreamingShrinkImageFilter = StreamingShrinkImageFilterType::New(); + + m_StreamingShrinkImageFilter->SetShrinkFactor(sampleRatioValue); + m_StreamingShrinkImageFilter->SetInput(m_VectorImage); + + m_VectorRescaleIntensityImageFilter = VectorRescaleIntensityImageFilterType::New(); + m_VectorRescaleIntensityImageFilter->SetInput(m_StreamingShrinkImageFilter->GetOutput()); //m_ResampleVectorImage); + m_VectorRescaleIntensityImageFilter->SetOutputMinimum(outMin); + m_VectorRescaleIntensityImageFilter->SetOutputMaximum(outMax); + + if (depth == 0) + { + m_VectorRescaleIntensityImageFilter->Update(); + inMin = m_VectorRescaleIntensityImageFilter->GetInputMinimum(); + inMax = m_VectorRescaleIntensityImageFilter->GetInputMaximum(); + } + else + { + m_VectorRescaleIntensityImageFilter->SetInputMinimum(inMin); + m_VectorRescaleIntensityImageFilter->SetInputMaximum(inMax); + m_VectorRescaleIntensityImageFilter->SetAutomaticInputMinMaxComputation(false); + } + + // New resample vector image + m_ResampleVectorImage = m_VectorRescaleIntensityImageFilter->GetOutput(); + } + else + { + m_VectorRescaleIntensityImageFilter = VectorRescaleIntensityImageFilterType::New(); + m_VectorRescaleIntensityImageFilter->SetInput(m_VectorImage); + m_VectorRescaleIntensityImageFilter->SetOutputMinimum(outMin); + m_VectorRescaleIntensityImageFilter->SetOutputMaximum(outMax); + + m_VectorRescaleIntensityImageFilter->SetInputMinimum(inMin); + m_VectorRescaleIntensityImageFilter->SetInputMaximum(inMax); + m_VectorRescaleIntensityImageFilter->SetAutomaticInputMinMaxComputation(false); + + m_ResampleVectorImage = m_VectorRescaleIntensityImageFilter->GetOutput(); + } + + m_ResampleVectorImage->UpdateOutputInformation(); + + // Get the image size + size = m_ResampleVectorImage->GetLargestPossibleRegion().GetSize(); + + sizeX = size[0]; + sizeY = size[1]; + + int x = 0; + int y = 0; + + // Tiling resample image + for (int tx = 0; tx < sizeX; tx += m_TileSize) + { + for (int ty = 0; ty < sizeY; ty += m_TileSize) + { + if ((tx + m_TileSize) >= sizeX) + { + extractIndex[0] = tx; + extractSize[0] = sizeX - tx; + } + else + { + extractIndex[0] = tx; + extractSize[0] = m_TileSize; + } + + if ((ty + m_TileSize) >= sizeY) + { + extractIndex[1] = ty; + extractSize[1] = sizeY - ty; + } + else + { + extractIndex[1] = ty; + extractSize[1] = m_TileSize; + } + + // Generate pathname + std::ostringstream path; + path << m_Path; + + ossimFilename cachingDir(path.str()); + cachingDir.createDirectory(); + + // Generate Tile filename + std::ostringstream ossFileName; + ossFileName << m_Path; + ossFileName << "/"; + ossFileName << y; + ossFileName << ".jpg"; + + std::cout <<"Writing the file "<< ossFileName.str() << std::endl; + + // Extract ROI + m_VectorImageExtractROIFilter = VectorImageExtractROIFilterType::New(); + + // Set extract roi parameters + m_VectorImageExtractROIFilter->SetStartX(extractIndex[0]); + m_VectorImageExtractROIFilter->SetStartY(extractIndex[1]); + m_VectorImageExtractROIFilter->SetSizeX(extractSize[0]); + m_VectorImageExtractROIFilter->SetSizeY(extractSize[1]); + + // Set Channel to extract + m_VectorImageExtractROIFilter->SetChannel(1);//m_ProductVector[m_CurrentProduct].m_Composition[0] + 1); + m_VectorImageExtractROIFilter->SetChannel(2);//m_ProductVector[m_CurrentProduct].m_Composition[1] + 1); + m_VectorImageExtractROIFilter->SetChannel(3);//m_ProductVector[m_CurrentProduct].m_Composition[2] + 1); + + // Set extract roi input + m_VectorImageExtractROIFilter->SetInput(m_ResampleVectorImage); + + // Configure writer + m_VectorWriter = VectorWriterType::New(); + m_VectorWriter->SetFileName(ossFileName.str().c_str()); + m_VectorWriter->SetInput(m_VectorImageExtractROIFilter->GetOutput()); + m_VectorWriter->WriteGeomFileOn(); + m_VectorWriter->Update(); + + /** TODO : Generate KML for this tile */ + // Search Lat/Lon box + m_Transform = TransformType::New(); + m_Transform->SetInputKeywordList(m_ResampleVectorImage->GetImageKeywordlist()); + m_Transform->SetInputProjectionRef(m_VectorImage->GetProjectionRef()); + m_Transform->SetOutputProjectionRef(wgsRef); + m_Transform->InstanciateTransform(); + + InputPointType inputPoint; + OutputPointType outputPoint; + IndexType indexTile; + SizeType sizeTile, demiSizeTile; + + sizeTile = extractSize; + demiSizeTile[0] = (sizeTile[0] / 2) - 1; + demiSizeTile[1] = (sizeTile[1] / 2) - 1; + + // Compute North value + indexTile[0] = extractIndex[0] + demiSizeTile[0]; + indexTile[1] = extractIndex[1]; + m_ResampleVectorImage->TransformIndexToPhysicalPoint(indexTile, inputPoint); + outputPoint = m_Transform->TransformPoint(inputPoint); + double north = outputPoint[1]; + + // Compute South value + indexTile[0] = extractIndex[0] + demiSizeTile[0]; + indexTile[1] = extractIndex[1] + sizeTile[1]; + m_ResampleVectorImage->TransformIndexToPhysicalPoint(indexTile, inputPoint); + outputPoint = m_Transform->TransformPoint(inputPoint); + double south = outputPoint[1]; + + // Compute East value + indexTile[0] = extractIndex[0] + sizeTile[0]; + indexTile[1] = extractIndex[1] + demiSizeTile[1]; + m_ResampleVectorImage->TransformIndexToPhysicalPoint(indexTile, inputPoint); + outputPoint = m_Transform->TransformPoint(inputPoint); + double east = outputPoint[0]; + + // Compute West value + indexTile[0] = extractIndex[0]; + indexTile[1] = extractIndex[1] + demiSizeTile[1]; + m_ResampleVectorImage->TransformIndexToPhysicalPoint(indexTile, inputPoint); + outputPoint = m_Transform->TransformPoint(inputPoint); + double west = outputPoint[0]; + + // Compute center value (lat / long) + indexTile[0] = extractIndex[0] + demiSizeTile[1]; + indexTile[1] = extractIndex[1] + demiSizeTile[1]; + m_ResampleVectorImage->TransformIndexToPhysicalPoint(indexTile, inputPoint); + outputPoint = m_Transform->TransformPoint(inputPoint); + double centerLat = outputPoint[1]; + double centerLong = outputPoint[0]; + + /** GX LAT LON **/ + // Compute lower left corner + indexTile[0] = extractIndex[0]; + indexTile[1] = extractIndex[1] + sizeTile[1]; + m_ResampleVectorImage->TransformIndexToPhysicalPoint(indexTile, inputPoint); + outputPoint = m_Transform->TransformPoint(inputPoint); + OutputPointType lowerLeftCorner = outputPoint; + + // Compute lower right corner + indexTile[0] = extractIndex[0] + sizeTile[0]; + indexTile[1] = extractIndex[1] + sizeTile[1]; + m_ResampleVectorImage->TransformIndexToPhysicalPoint(indexTile, inputPoint); + outputPoint = m_Transform->TransformPoint(inputPoint); + OutputPointType lowerRightCorner = outputPoint; + + // Compute upper right corner + indexTile[0] = extractIndex[0] + sizeTile[0]; + indexTile[1] = extractIndex[1]; + m_ResampleVectorImage->TransformIndexToPhysicalPoint(indexTile, inputPoint); + outputPoint = m_Transform->TransformPoint(inputPoint); + OutputPointType upperRightCorner = outputPoint; + + // Compute upper left corner + indexTile[0] = extractIndex[0]; + indexTile[1] = extractIndex[1]; + m_ResampleVectorImage->TransformIndexToPhysicalPoint(indexTile, inputPoint); + outputPoint = m_Transform->TransformPoint(inputPoint); + OutputPointType upperLeftCorner = outputPoint; + + /** END GX LAT LON */ + + // Create KML - Filename - PathName - tile number - North - South - East - West + if (sampleRatioValue == 1) + { + if (!m_UseExtendMode) // Extended format + this->GenerateKML(path.str(), depth, x, y, north, south, east, west); + else + this->GenerateKMLExtended(path.str(), depth, + x, y, lowerLeftCorner, + lowerRightCorner, + upperRightCorner, upperLeftCorner); + } + else + { + // Search tiles to link + int tileXStart = extractIndex[0] / (m_TileSize / 2); + int tileYStart = extractIndex[1] / (m_TileSize / 2); + + // Create KML with link + if (!m_UseExtendMode) + this->GenerateKMLWithLink(path.str(), depth, x, y, tileXStart, tileYStart, + north, south, east, west, centerLong, centerLat); + else + this->GenerateKMLExtendedWithLink( + path.str(), depth, x, y, tileXStart, tileYStart, + lowerLeftCorner, lowerRightCorner, upperRightCorner, upperLeftCorner, + centerLong, centerLat); + } + + if (depth == 0) + { + // Add the headers and the basic stuffs in the kml only once. + if (curIdx == 0) + { + this->RootKmlProcess(north, south, east, west); + } + + // Add the bounding box kml + //this->BoundingBoxKmlProcess(north, south, east, west); : + //To Add After######################### + } + + // Add the files to the kmz file + // Relative path to the root directory in the kmz file + std::ostringstream jpg_in_kmz, kml_in_kmz; + jpg_in_kmz << m_CurrentImageName << "/" << depth << "/" << x << "/" << y << ".jpg"; + kml_in_kmz << m_CurrentImageName << "/" << depth << "/" << x << "/" << y << m_KmlExtension; + + // Absolute path where are stored the files + std::ostringstream jpg_absolute_path, kml_absolute_path; + jpg_absolute_path << m_Path << "/" << y << ".jpg"; + kml_absolute_path << m_Path << "/" << y << m_KmlExtension; + + //Add the files to the kmz + this->AddFileToKMZ(jpg_absolute_path, jpg_in_kmz); + this->AddFileToKMZ(kml_absolute_path, kml_in_kmz); + + // Remove the unecessary files with stdio method :remove + if (remove(kml_absolute_path.str().c_str()) || remove(jpg_absolute_path.str().c_str())) + { + itkExceptionMacro( + << "Error while deleting the file" << kml_absolute_path.str() << "or file " << jpg_absolute_path.str()); + } + + y++; + } + x++; + y = 0; + } + } +} + + +/** +* +*/ +template <class TInputImage> +int +KmzProductWriter<TInputImage> +::AddFileToKMZ(std::ostringstream& absolutePath, std::ostringstream& kmz_in_path) +{ + std::string absolute = absolutePath.str(); + std::string relative = kmz_in_path.str(); + std::string file_data; + int errs = 0; + if (!kmlbase::File::ReadFileToString(absolute, &file_data)) + { + itkExceptionMacro(<< "Error while reading file " << absolute); + } + else + { + m_KmzFile->AddFile(file_data, relative); + } + + return errs; +} + + +/** + * Actually the root kml is not fully generated : + * It generates only the part till the network link + * In case of multiple inputs, other network liks are + * needed. See the method Add NetworkLinkToRootKML. + */ +template <class TInputImage> +void +KmzProductWriter<TInputImage> +::GenerateKMLRoot(std::string title, + double north, + double south, + double east, + double west, + bool extended) +{ + // Give a name to the root file + std::ostringstream kmlname; + kmlname << m_Path; + kmlname << "/"; + kmlname << m_FileName; + kmlname << m_KmlExtension; + m_RootKmlFile.open(kmlname.str().c_str()); + m_RootKmlFile << fixed << setprecision(6); + + m_RootKmlFile << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << std::endl; + m_RootKmlFile << "<kml xmlns=\"http://www.opengis.net/kml/2.2\"" << std::endl; + m_RootKmlFile << " xmlns:gx=\"http://www.google.com/kml/ext/2.2\">" << std::endl; + m_RootKmlFile << "\t<Document>" << std::endl; + m_RootKmlFile << "\t\t<name>" << title << "</name>" << std::endl; + m_RootKmlFile << "\t\t<description></description>" << std::endl; + m_RootKmlFile << "\t\t<LookAt>" << std::endl; + m_RootKmlFile << "\t\t\t<longitude>" << (east + west) / 2. << "</longitude>" << std::endl; + m_RootKmlFile << "\t\t\t<latitude>" << (south + north) / 2. << "</latitude>" << std::endl; + m_RootKmlFile << "\t\t\t<altitude>35000</altitude>" << std::endl; + m_RootKmlFile << "\t\t\t<range>35000</range>" << std::endl; + m_RootKmlFile << "\t\t</LookAt>" << std::endl; +} + +/** + */ +template <class TInputImage> +void +KmzProductWriter<TInputImage> +::RootKmlProcess(double north, double south, double east, double west) +{ + bool extended = m_UseExtendMode; + this->GenerateKMLRoot(m_FileName, north, south, east, west, extended); + + // Add the legend for this product if any + //this->AddCurrentProductLegends(0); + + // Add the flag netwotk link for each input image + this->AddNetworkLinkToRootKML(north, south, east, west, m_CurrentImageName, true, 0); + + // Root kml must be the first kml created + // Mutliple Inputs + for (unsigned int i = 1; i < 1; i++) + { + // Method to write a legend in the kmz + //this->AddCurrentProductLegends(i); + + // Get the filename + //std::string fname = this->GetInputDataDescription<FloatingVectorImageType>("InputImage", i); + std::string currentImageName = this->GetCuttenFileName(m_FileName, i); + + // Get the pĥysical coordinate of the center + SizeType tempSize = m_VectorImage->GetLargestPossibleRegion().GetSize(); + InputPointType tempPoint, tempPointOrigin; + IndexType tempIndex, tempIndexOrigin; + tempIndex[0] = tempSize[0]; + tempIndex[1] = tempSize[1]; + tempIndexOrigin.Fill(0); + + m_VectorImage->TransformIndexToPhysicalPoint(tempIndex, tempPoint); + m_VectorImage->TransformIndexToPhysicalPoint(tempIndexOrigin, + tempPointOrigin); + + // Compute the transform + TransformType::Pointer tempTransform = TransformType::New(); + tempTransform->SetInputKeywordList(m_VectorImage->GetImageKeywordlist()); + tempTransform->SetInputProjectionRef(m_VectorImage->GetProjectionRef()); + tempTransform->InstanciateTransform(); + + OutputPointType tempOutputPoint, tempOutputPointOrigin; + tempOutputPoint = tempTransform->TransformPoint(tempPoint); + tempOutputPointOrigin = tempTransform->TransformPoint(tempPointOrigin); + + this->AddNetworkLinkToRootKML(tempOutputPointOrigin[1], + tempOutputPoint[1], tempOutputPointOrigin[0], + tempOutputPoint[0], currentImageName, false, + i); + } + + // Last thing to do is to close the root kml + this->CloseRootKML(); + + // Add the root kml in the kmz + std::ostringstream root_in_kmz; + root_in_kmz << m_FileName << m_KmlExtension; + + std::ostringstream root_absolute_path; + root_absolute_path << m_Path << "/" << root_in_kmz.str(); + + // Add the root file in the kmz + this->AddFileToKMZ(root_absolute_path, root_in_kmz); + + // Remove the root files with stdio method :remove + if (remove(root_absolute_path.str().c_str()) != 0) + { + itkExceptionMacro(<< "Error while deleting the file" << root_absolute_path.str()); + } +} + +/** + * Close the root kml + */ +template <class TInputImage> +void +KmzProductWriter<TInputImage> +::CloseRootKML() +{ +// if (m_HasLogo) +// { +// RegionType logoReg = m_Logo->GetLargestPossibleRegion(); +// SizeType logoSize = logoReg.GetSize(); +// double lx = static_cast<double>(logoSize[0]); +// double ly = static_cast<double>(logoSize[1]); +// int sizey = 150; +// int sizex = static_cast<int>((lx / ly * sizey)); + +// /** LOGO **/ +// m_RootKmlFile << "\t\t<ScreenOverlay>" << std::endl; +// m_RootKmlFile << "\t\t\t<Icon>" << std::endl; +// m_RootKmlFile << "\t\t\t\t<href>logo.jpeg</href>" << std::endl; +// m_RootKmlFile << "\t\t\t</Icon>" << std::endl; +// m_RootKmlFile << "\t\t\t<name>Logo</name>" << std::endl; +// m_RootKmlFile << "\t\t\t<overlayXY x=\"1\" y=\"1\" xunits=\"fraction\" yunits=\"fraction\"/>" << std::endl; +// m_RootKmlFile << "\t\t\t<screenXY x=\"1\" y=\"1\" xunits=\"fraction\" yunits=\"fraction\"/>" << std::endl; +// m_RootKmlFile << "\t\t\t<size x=\"" << sizex << "\" y=\"" << sizey << +// "\" xunits=\"pixels\" yunits=\"pixels\"/> " << std::endl; +// m_RootKmlFile << "\t\t</ScreenOverlay>" << std::endl; + +// /** LOGO **/ +// } + + m_RootKmlFile << "\t</Document>" << std::endl; + m_RootKmlFile << "</kml>" << std::endl; + m_RootKmlFile.close(); +} + + +/** + * Add A networkLink to the root kml + * + */ +template <class TInputImage> +void +KmzProductWriter<TInputImage> +::AddNetworkLinkToRootKML(double north, + double south, + double east, + double west, + std::string directory, + bool addRegion, + unsigned int pos) +{ + m_RootKmlFile << "\t\t<Document>" << std::endl; + m_RootKmlFile << "\t\t\t<name>" << m_FileName<< "</name>" << std::endl; + //m_RootKmlFile << "\t\t\t<Description>" << m_ProductVector[pos].m_Description << "</Description>" << std::endl; + m_RootKmlFile << "\t\t\t<LookAt>" << std::endl; + m_RootKmlFile << "\t\t\t\t<longitude>" << (east + west) / 2. << "</longitude>" << std::endl; + m_RootKmlFile << "\t\t\t\t<latitude>" << (south + north) / 2. << "</latitude>" << std::endl; + m_RootKmlFile << "\t\t\t\t<altitude>35000</altitude>" << std::endl; + m_RootKmlFile << "\t\t\t\t<range>35000</range>" << std::endl; + m_RootKmlFile << "\t\t\t</LookAt>" << std::endl; + + // Georeferenced Products + // Add network link + // If not geo add a ground Overlay with image + // as an icon +// if (this->IsProductHaveMetaData(pos)) +// { + m_RootKmlFile << "\t\t\t<NetworkLink>" << std::endl; + m_RootKmlFile << "\t\t\t\t<name>" << m_FileName<< "</name>" << std::endl; + m_RootKmlFile << "\t\t\t\t<open>1</open>" << std::endl; + m_RootKmlFile << "\t\t\t<Style>" << std::endl; + m_RootKmlFile << "\t\t\t\t<ListStyle id=\"hideChildren\">" << std::endl; + m_RootKmlFile << "\t\t\t\t\t<listItemType>checkHideChildren</listItemType>" << std::endl; + m_RootKmlFile << "\t\t\t\t</ListStyle>" << std::endl; + m_RootKmlFile << "\t\t\t</Style>" << std::endl; + if (addRegion) + { + m_RootKmlFile << "\t\t\t\t<Region>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t<Lod>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t\t<minLodPixels>" << m_TileSize / 2 << "</minLodPixels>" << std::endl; + /** If the last depth, put level of detail LOD to infinite (ie -1)*/ + if (m_CurrentDepth == m_MaxDepth) + m_RootKmlFile << "\t\t\t\t\t\t<maxLodPixels>-1</maxLodPixels>" << std::endl; + else + m_RootKmlFile << "\t\t\t\t\t\t<maxLodPixels>" << m_TileSize * 4 << "</maxLodPixels>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t</Lod>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t<LatLonAltBox>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t\t<north>" << north << "</north>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t\t<south>" << south << "</south>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t\t<east>" << east << "</east>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t\t<west>" << west << "</west>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t</LatLonAltBox>" << std::endl; + m_RootKmlFile << "\t\t\t\t</Region>" << std::endl; + } + + m_RootKmlFile << "\t\t\t\t<Link>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t<href>" << directory << "/0/0/0" << m_KmlExtension << "</href>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t<viewRefreshMode>onRegion</viewRefreshMode>" << std::endl; + m_RootKmlFile << "\t\t\t\t</Link>" << std::endl; + m_RootKmlFile << "\t\t\t</NetworkLink>" << std::endl; +// } +// else +// { +// m_RootKmlFile << "\t\t\t<GroundOverlay>" << std::endl; +// m_RootKmlFile << "\t\t\t\t<name>" << m_FileName<< "</name>" << std::endl; +// m_RootKmlFile << "\t\t\t\t<Icon>" << std::endl; +// m_RootKmlFile << "\t\t\t\t\t<href>" << directory << "/0.jpg" << "</href>" << std::endl; +// m_RootKmlFile << "\t\t\t\t</Icon>" << std::endl; + +// if (!m_UseExtendMode) +// { +// m_RootKmlFile << "\t\t\t\t<LatLonBox>" << std::endl; +// m_RootKmlFile << "\t\t\t\t\t<north>" << north << "</north>" << std::endl; +// m_RootKmlFile << "\t\t\t\t\t<south>" << south << "</south>" << std::endl; +// m_RootKmlFile << "\t\t\t\t\t<east>" << east << "</east>" << std::endl; +// m_RootKmlFile << "\t\t\t\t\t<west>" << west << "</west>" << std::endl; +// m_RootKmlFile << "\t\t\t\t</LatLonBox>" << std::endl; +// } +// else +// { +// m_RootKmlFile << "\t\t\t<gx:LatLonQuad>" << std::endl; +// m_RootKmlFile << "\t\t\t\t<coordinates>" << std::endl; +// m_RootKmlFile << " " << m_LowerLeftCorner[0] << "," << m_LowerLeftCorner[1]; +// m_RootKmlFile << " " << m_LowerRightCorner[0] << "," << m_LowerRightCorner[1]; +// m_RootKmlFile << " " << m_UpperRightCorner[0] << "," << m_UpperRightCorner[1]; +// m_RootKmlFile << " " << m_UpperLeftCorner[0] << "," << m_UpperRightCorner[1] << std::endl; +// m_RootKmlFile << "\t\t\t\t</coordinates>" << std::endl; +// m_RootKmlFile << "\t\t\t</gx:LatLonQuad>" << std::endl; +// } +// m_RootKmlFile << "\t\t\t</GroundOverlay>" << std::endl; +// } + + m_RootKmlFile << "\t\t\t<Folder>" << std::endl; + m_RootKmlFile << "\t\t\t\t<name>The bounding box </name>" << std::endl; + m_RootKmlFile << "\t\t\t\t<Style>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t<ListStyle id=\"hideChildren\">" << std::endl; + m_RootKmlFile << "\t\t\t\t\t\t<listItemType>checkHideChildren</listItemType>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t</ListStyle>" << std::endl; + m_RootKmlFile << "\t\t\t\t</Style>" << std::endl; + m_RootKmlFile << "\t\t\t\t<NetworkLink>" << std::endl; + m_RootKmlFile << "\t\t\t\t<Region>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t<Lod>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t\t<minLodPixels>" << m_TileSize / 2 << "</minLodPixels>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t\t<maxLodPixels>-1</maxLodPixels>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t</Lod>" << std::endl; + m_RootKmlFile << "\t\t\t\t</Region>" << std::endl; + m_RootKmlFile << "\t\t\t\t<Link>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t<href>bounds/bound_" << pos << m_KmlExtension << "</href>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t<viewRefreshMode>onRegion</viewRefreshMode>" << std::endl; + m_RootKmlFile << "\t\t\t\t</Link>" << std::endl; + m_RootKmlFile << "\t\t\t\t</NetworkLink>" << std::endl; + m_RootKmlFile << "\t\t\t</Folder>" << std::endl; + + // Add a placemark with the images used as legend + // If any + //this->AddLegendToRootKml(north, south, east, west, pos); + + m_RootKmlFile << "\t\t</Document>" << std::endl; +} + + +template <class TInputImage> +void +KmzProductWriter<TInputImage> +::GenerateKMLExtended(std::string pathname, int depth, int x, int y, + OutputPointType lowerLeft, OutputPointType lowerRight, + OutputPointType upperRight, OutputPointType upperLeft) +{ + std::ostringstream kmlname; + kmlname << pathname; + kmlname << "/"; + kmlname << y << "xt.kml"; + std::ofstream fileTest(kmlname.str().c_str()); + + fileTest << fixed << setprecision(6); + + fileTest << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << std::endl; + fileTest << "<kml xmlns=\"http://www.opengis.net/kml/2.2\"" << std::endl; + fileTest << " xmlns:gx=\"http://www.google.com/kml/ext/2.2\">" << std::endl; + fileTest << "\t<Document>" << std::endl; + fileTest << "\t\t<name>" << y << "xt.kml</name>" << std::endl; + fileTest << "\t\t<Region>" << std::endl; + fileTest << "\t\t\t<Lod>" << std::endl; + fileTest << "\t\t\t\t<minLodPixels>" << m_TileSize / 2 << "</minLodPixels>" << std::endl; + fileTest << "\t\t\t\t<maxLodPixels>-1</maxLodPixels>" << std::endl; + fileTest << "\t\t\t</Lod>" << std::endl; + fileTest << "\t\t\t<gx:LatLonQuad>" << std::endl; + fileTest << "\t\t\t\t<coordinates>" << std::endl; + fileTest << "\t\t\t\t\t" << lowerLeft[0] << "," << lowerLeft[1]; + fileTest << " " << lowerRight[0] << "," << lowerRight[1]; + fileTest << " " << upperRight[0] << "," << upperRight[1]; + fileTest << " " << upperLeft[0] << "," << upperLeft[1] << std::endl; + fileTest << "\t\t\t\t</coordinates>" << std::endl; + fileTest << "\t\t\t</gx:LatLonQuad>" << std::endl; + fileTest << "\t\t</Region>" << std::endl; + fileTest << "\t\t<GroundOverlay>" << std::endl; + fileTest << "\t\t\t<drawOrder>" << depth + (m_CurIdx * m_MaxDepth) << "</drawOrder>" << std::endl; + fileTest << "\t\t\t<Icon>" << std::endl; + fileTest << "\t\t\t\t<href>" << y << ".jpg" << "</href>" << std::endl; + fileTest << "\t\t\t</Icon>" << std::endl; + fileTest << "\t\t\t<gx:LatLonQuad>" << std::endl; + fileTest << "\t\t\t\t<coordinates>" << std::endl; + fileTest << "\t\t\t\t\t" << lowerLeft[0] << "," << lowerLeft[1]; + fileTest << " " << lowerRight[0] << "," << lowerRight[1]; + fileTest << " " << upperRight[0] << "," << upperRight[1]; + fileTest << " " << upperLeft[0] << "," << upperLeft[1] << std::endl; + fileTest << "\t\t\t\t</coordinates>" << std::endl; + fileTest << "\t\t\t</gx:LatLonQuad>" << std::endl; + fileTest << "\t\t</GroundOverlay>" << std::endl; + fileTest << "\t</Document>" << std::endl; + fileTest << "</kml>" << std::endl; + + fileTest.close(); +} + + +template <class TInputImage> +void +KmzProductWriter<TInputImage> +::GenerateKML(std::string pathname, int depth, int x, int y, double north, double south, double east, double west) +{ + std::ostringstream kmlname; + kmlname << pathname; + kmlname << "/"; + kmlname << y << ".kml"; + std::ofstream fileTest(kmlname.str().c_str()); + + fileTest << fixed << setprecision(6); + + fileTest << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << std::endl; + fileTest << "<kml xmlns=\"http://www.opengis.net/kml/2.2\"" << std::endl; + fileTest << " xmlns:gx=\"http://www.google.com/kml/ext/2.2\">" << std::endl; + fileTest << "\t<Document>" << std::endl; + fileTest << "\t\t<name>" << y << ".kml</name>" << std::endl; + fileTest << "\t\t<Region>" << std::endl; + fileTest << "\t\t\t<Lod>" << std::endl; + fileTest << "\t\t\t\t<minLodPixels>" << m_TileSize / 2 << "</minLodPixels>" << std::endl; + if (m_CurrentDepth == m_MaxDepth) fileTest << "\t\t\t\t<maxLodPixels>-1</maxLodPixels>" << std::endl; + else fileTest << "\t\t\t\t<maxLodPixels>" << m_TileSize * 4 << "</maxLodPixels>" << std::endl; + fileTest << "\t\t\t</Lod>" << std::endl; + fileTest << "\t\t\t<LatLonAltBox>" << std::endl; + fileTest << "\t\t\t\t<north>" << north << "</north>" << std::endl; + fileTest << "\t\t\t\t<south>" << south << "</south>" << std::endl; + fileTest << "\t\t\t\t<east>" << east << "</east>" << std::endl; + fileTest << "\t\t\t\t<west>" << west << "</west>" << std::endl; + fileTest << "\t\t\t</LatLonAltBox>" << std::endl; + fileTest << "\t\t</Region>" << std::endl; + fileTest << "\t\t<GroundOverlay>" << std::endl; + fileTest << "\t\t\t<drawOrder>" << depth + (m_CurIdx * m_MaxDepth) << "</drawOrder>" << std::endl; + fileTest << "\t\t\t<Icon>" << std::endl; + fileTest << "\t\t\t\t<href>" << y << ".jpg" << "</href>" << std::endl; + fileTest << "\t\t\t</Icon>" << std::endl; + fileTest << "\t\t\t<LatLonAltBox>" << std::endl; + fileTest << "\t\t\t\t<north>" << north << "</north>" << std::endl; + fileTest << "\t\t\t\t<south>" << south << "</south>" << std::endl; + fileTest << "\t\t\t\t<east>" << east << "</east>" << std::endl; + fileTest << "\t\t\t\t<west>" << west << "</west>" << std::endl; + fileTest << "\t\t\t</LatLonAltBox>" << std::endl; + fileTest << "\t\t</GroundOverlay>" << std::endl; + fileTest << "\t</Document>" << std::endl; + fileTest << "</kml>" << std::endl; + + fileTest.close(); +} + +template <class TInputImage> +void +KmzProductWriter<TInputImage> +::GenerateKMLExtendedWithLink(std::string pathname, + int depth, int x, int y, int tileStartX, int tileStartY, + OutputPointType lowerLeft, OutputPointType lowerRight, + OutputPointType upperRight, OutputPointType upperLeft, + double centerLong, double centerLat) +{ + std::ostringstream kmlname; + kmlname << pathname; + kmlname << "/"; + kmlname << y << "xt.kml"; + std::ofstream fileTest(kmlname.str().c_str()); + + fileTest << fixed << setprecision(6); + + fileTest << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << std::endl; + fileTest << "<kml xmlns=\"http://www.opengis.net/kml/2.2\"" << std::endl; + fileTest << " xmlns:gx=\"http://www.google.com/kml/ext/2.2\">" << std::endl; + fileTest << "\t<Document>" << std::endl; + fileTest << "\t\t<name>" << y << "xt.kml</name>" << std::endl; + fileTest << "\t\t<Region>" << std::endl; + fileTest << "\t\t\t<Lod>" << std::endl; + fileTest << "\t\t\t\t<minLodPixels>" << m_TileSize / 2 << "</minLodPixels>" << std::endl; + fileTest << "\t\t\t\t<maxLodPixels>-1</maxLodPixels>" << std::endl; + fileTest << "\t\t\t</Lod>" << std::endl; + fileTest << "\t\t\t<gx:LatLonQuad>" << std::endl; + fileTest << "\t\t\t\t<coordinates>" << std::endl; + fileTest << "\t\t\t\t\t" << lowerLeft[0] << "," << lowerLeft[1]; + fileTest << " " << lowerRight[0] << "," << lowerRight[1]; + fileTest << " " << upperRight[0] << "," << upperRight[1]; + fileTest << " " << upperLeft[0] << "," << upperLeft[1] << std::endl; + fileTest << "\t\t\t\t</coordinates>" << std::endl; + fileTest << "\t\t\t</gx:LatLonQuad>" << std::endl; + fileTest << "\t\t</Region>" << std::endl; + fileTest << "\t\t<GroundOverlay>" << std::endl; + fileTest << "\t\t\t<drawOrder>" << depth + (m_CurIdx * m_MaxDepth) << "</drawOrder>" << std::endl; + fileTest << "\t\t\t<Icon>" << std::endl; + fileTest << "\t\t\t\t<href>" << y << ".jpg" << "</href>" << std::endl; + fileTest << "\t\t\t</Icon>" << std::endl; + fileTest << "\t\t\t<gx:LatLonQuad>" << std::endl; + fileTest << "\t\t\t\t<coordinates>" << std::endl; + fileTest << "\t\t\t\t\t" << lowerLeft[0] << "," << lowerLeft[1]; + fileTest << " " << lowerRight[0] << "," << lowerRight[1]; + fileTest << " " << upperRight[0] << "," << upperRight[1]; + fileTest << " " << upperLeft[0] << "," << upperLeft[1] << std::endl; + fileTest << "\t\t\t\t</coordinates>" << std::endl; + fileTest << "\t\t\t</gx:LatLonQuad>" << std::endl; + fileTest << "\t\t</GroundOverlay>" << std::endl; + + /* Sous tuile 1 */ + std::ostringstream fileTile1; + fileTile1 << "../../"; + fileTile1 << depth + 1; + fileTile1 << "/"; + fileTile1 << tileStartX; + fileTile1 << "/"; + fileTile1 << tileStartY; + + fileTest << "\t\t<NetworkLink>" << std::endl; + fileTest << "\t\t\t<name>" << fileTile1.str() << ".jpg</name>" << std::endl; + fileTest << "\t\t\t<Region>" << std::endl; + fileTest << "\t\t\t\t<Lod>" << std::endl; + fileTest << "\t\t\t\t\t<minLodPixels>" << m_TileSize / 2 << "</minLodPixels>" << std::endl; + fileTest << "\t\t\t\t\t<maxLodPixels>-1</maxLodPixels>" << std::endl; + fileTest << "\t\t\t\t</Lod>" << std::endl; + fileTest << "\t\t\t\t<gx:LatLonQuad>" << std::endl; + fileTest << "\t\t\t\t\t<coordinates>" << std::endl; + fileTest << "\t\t\t\t\t\t" << lowerLeft[0] << "," << centerLat; + fileTest << " " << centerLong << "," << centerLat; + fileTest << " " << centerLong << "," << upperLeft[1]; + fileTest << " " << upperLeft[0] << "," << upperLeft[1] << std::endl; + fileTest << "\t\t\t\t\t</coordinates>" << std::endl; + fileTest << "\t\t\t\t</gx:LatLonQuad>" << std::endl; + fileTest << "\t\t\t</Region>" << std::endl; + fileTest << "\t\t\t<Link>" << std::endl; + fileTest << "\t\t\t\t<href>" << fileTile1.str() << "xt.kml</href>" << std::endl; + fileTest << "\t\t\t\t<viewRefreshMode>onRegion</viewRefreshMode>" << std::endl; + fileTest << "\t\t\t\t<viewFormat/>" << std::endl; + fileTest << "\t\t\t</Link>" << std::endl; + fileTest << "\t\t</NetworkLink>" << std::endl; + + /* Sous tuile 2 */ + std::ostringstream fileTile2; + fileTile2 << "../../"; + fileTile2 << depth + 1; + fileTile2 << "/"; + fileTile2 << tileStartX + 1; + fileTile2 << "/"; + fileTile2 << tileStartY; + + fileTest << "\t\t<NetworkLink>" << std::endl; + fileTest << "\t\t\t<name>" << fileTile2.str() << ".jpg</name>" << std::endl; + fileTest << "\t\t\t<Region>" << std::endl; + fileTest << "\t\t\t<Lod>" << std::endl; + fileTest << "\t\t\t\t<minLodPixels>" << m_TileSize / 2 << "</minLodPixels>" << std::endl; + fileTest << "\t\t\t\t<maxLodPixels>-1</maxLodPixels>" << std::endl; + fileTest << "\t\t\t</Lod>" << std::endl; + fileTest << "\t\t\t\t<gx:LatLonQuad>" << std::endl; + fileTest << "\t\t\t\t\t<coordinates>" << std::endl; + fileTest << "\t\t\t\t\t\t" << centerLong << "," << centerLat; + fileTest << " " << lowerRight[0] << "," << centerLat; + fileTest << " " << upperRight[0] << "," << upperRight[1]; + fileTest << " " << centerLong << "," << upperLeft[1] << std::endl; + fileTest << "\t\t\t\t\t</coordinates>" << std::endl; + fileTest << "\t\t\t\t</gx:LatLonQuad>" << std::endl; + fileTest << "\t\t\t</Region>" << std::endl; + fileTest << "\t\t\t<Link>" << std::endl; + fileTest << "\t\t\t\t<href>" << fileTile2.str() << "xt.kml</href>" << std::endl; + fileTest << "\t\t\t\t<viewRefreshMode>onRegion</viewRefreshMode>" << std::endl; + fileTest << "\t\t\t\t<viewFormat/>" << std::endl; + fileTest << "\t\t\t</Link>" << std::endl; + fileTest << "\t\t</NetworkLink>" << std::endl; + + /* Sous tuile 3 */ + std::ostringstream fileTile3; + fileTile3 << "../../"; + fileTile3 << depth + 1; + fileTile3 << "/"; + fileTile3 << tileStartX + 1; + fileTile3 << "/"; + fileTile3 << tileStartY + 1; + + fileTest << "\t\t<NetworkLink>" << std::endl; + fileTest << "\t\t\t<name>" << fileTile3.str() << ".jpg</name>" << std::endl; + fileTest << "\t\t\t<Region>" << std::endl; + fileTest << "\t\t\t\t<Lod>" << std::endl; + fileTest << "\t\t\t\t\t<minLodPixels>" << m_TileSize / 2 << "</minLodPixels>" << std::endl; + fileTest << "\t\t\t\t\t<maxLodPixels>-1</maxLodPixels>" << std::endl; + fileTest << "\t\t\t\t</Lod>" << std::endl; + fileTest << "\t\t\t\t<gx:LatLonQuad>" << std::endl; + fileTest << "\t\t\t\t\t<coordinates>" << std::endl; + fileTest << "\t\t\t\t\t\t" << centerLong << "," << lowerLeft[1]; + fileTest << " " << lowerRight[0] << "," << lowerRight[1]; + fileTest << " " << upperRight[0] << "," << centerLat; + fileTest << " " << centerLong << "," << centerLat << std::endl; + fileTest << "\t\t\t\t\t</coordinates>" << std::endl; + fileTest << "\t\t\t\t</gx:LatLonQuad>" << std::endl; + fileTest << "\t\t\t</Region>" << std::endl; + fileTest << "\t\t\t<Link>" << std::endl; + fileTest << "\t\t\t\t<href>" << fileTile3.str() << "xt.kml</href>" << std::endl; + fileTest << "\t\t\t\t<viewRefreshMode>onRegion</viewRefreshMode>" << std::endl; + fileTest << "\t\t\t\t<viewFormat/>" << std::endl; + fileTest << "\t\t\t</Link>" << std::endl; + fileTest << "\t\t</NetworkLink>" << std::endl; + + /* Sous tuile 4 */ + std::ostringstream fileTile4; + fileTile4 << "../../"; + fileTile4 << depth + 1; + fileTile4 << "/"; + fileTile4 << tileStartX; + fileTile4 << "/"; + fileTile4 << tileStartY + 1; + + fileTest << "\t\t<NetworkLink>" << std::endl; + fileTest << "\t\t\t<name>" << fileTile4.str() << ".jpg</name>" << std::endl; + fileTest << "\t\t\t<Region>" << std::endl; + fileTest << "\t\t\t\t<Lod>" << std::endl; + fileTest << "\t\t\t\t\t<minLodPixels>" << m_TileSize / 2 << "</minLodPixels>" << std::endl; + fileTest << "\t\t\t\t\t<maxLodPixels>-1</maxLodPixels>" << std::endl; + fileTest << "\t\t\t\t</Lod>" << std::endl; + fileTest << "\t\t\t\t<gx:LatLonQuad>" << std::endl; + fileTest << "\t\t\t\t\t<coordinates>" << std::endl; + fileTest << "\t\t\t\t\t\t" << lowerLeft[0] << "," << lowerLeft[1]; + fileTest << "\t\t\t\t\t\t" << centerLong << "," << lowerRight[1]; + fileTest << "\t\t\t\t\t\t" << centerLong << "," << centerLat; + fileTest << "\t\t\t\t\t\t" << upperLeft[0] << "," << centerLat << std::endl; + fileTest << "\t\t\t\t\t</coordinates>" << std::endl; + fileTest << "\t\t\t\t</gx:LatLonQuad>" << std::endl; + fileTest << "\t\t\t</Region>" << std::endl; + fileTest << "\t\t\t<Link>" << std::endl; + fileTest << "\t\t\t\t<href>" << fileTile4.str() << "xt.kml</href>" << std::endl; + fileTest << "\t\t\t\t<viewRefreshMode>onRegion</viewRefreshMode>" << std::endl; + fileTest << "\t\t\t\t<viewFormat/>" << std::endl; + fileTest << "\t\t\t</Link>" << std::endl; + fileTest << "\t\t</NetworkLink>" << std::endl; + + fileTest << "\t</Document>" << std::endl; + fileTest << "</kml>" << std::endl; + fileTest.close(); + +} + +template <class TInputImage> +void +KmzProductWriter<TInputImage> +::GenerateKMLWithLink(std::string pathname, + int depth, int x, int y, int tileStartX, int tileStartY, + double north, double south, double east, double west, double centerLong, double centerLat) +{ + std::ostringstream kmlname; + kmlname << pathname; + kmlname << "/"; + kmlname << y << ".kml"; + std::ofstream fileTest(kmlname.str().c_str()); + + fileTest << fixed << setprecision(6); + + fileTest << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << std::endl; + fileTest << "<kml xmlns=\"http://www.opengis.net/kml/2.2\"" << std::endl; + fileTest << " xmlns:gx=\"http://www.google.com/kml/ext/2.2\">" << std::endl; + fileTest << "\t<Document>" << std::endl; + fileTest << "\t\t<name>" << y << ".kml</name>" << std::endl; + fileTest << "\t\t<Region>" << std::endl; + fileTest << "\t\t\t<Lod>" << std::endl; + fileTest << "\t\t\t\t<minLodPixels>" << m_TileSize / 2 << "</minLodPixels>" << std::endl; + if (m_CurrentDepth == m_MaxDepth) + fileTest << "\t\t\t\t<maxLodPixels>-1</maxLodPixels>" << std::endl; + else + fileTest << "\t\t\t\t<maxLodPixels>" << m_TileSize * 2 << "</maxLodPixels>" << std::endl; + fileTest << "\t\t\t</Lod>" << std::endl; + fileTest << "\t\t\t<LatLonAltBox>" << std::endl; + fileTest << "\t\t\t\t<north>" << north << "</north>" << std::endl; + fileTest << "\t\t\t\t<south>" << south << "</south>" << std::endl; + fileTest << "\t\t\t\t<east>" << east << "</east>" << std::endl; + fileTest << "\t\t\t\t<west>" << west << "</west>" << std::endl; + fileTest << "\t\t\t</LatLonAltBox>" << std::endl; + fileTest << "\t\t</Region>" << std::endl; + fileTest << "\t\t<GroundOverlay>" << std::endl; + fileTest << "\t\t\t<drawOrder>" << depth + (m_CurIdx * m_MaxDepth) << "</drawOrder>" << std::endl; + fileTest << "\t\t\t<Icon>" << std::endl; + fileTest << "\t\t\t\t<href>" << y << ".jpg" << "</href>" << std::endl; + fileTest << "\t\t\t</Icon>" << std::endl; + fileTest << "\t\t\t<LatLonAltBox>" << std::endl; + fileTest << "\t\t\t\t<north>" << north << "</north>" << std::endl; + fileTest << "\t\t\t\t<south>" << south << "</south>" << std::endl; + fileTest << "\t\t\t\t<east>" << east << "</east>" << std::endl; + fileTest << "\t\t\t\t<west>" << west << "</west>" << std::endl; + fileTest << "\t\t\t</LatLonAltBox>" << std::endl; + fileTest << "\t\t</GroundOverlay>" << std::endl; + + /* Sous tuile 1 */ + std::ostringstream fileTile1; + fileTile1 << "../../"; + fileTile1 << depth + 1; + fileTile1 << "/"; + fileTile1 << tileStartX; + fileTile1 << "/"; + fileTile1 << tileStartY; + + fileTest << "\t\t<NetworkLink>" << std::endl; + fileTest << "\t\t\t<name>" << fileTile1.str() << ".jpg</name>" << std::endl; + fileTest << "\t\t\t<Region>" << std::endl; + fileTest << "\t\t\t\t<Lod>" << std::endl; + fileTest << "\t\t\t\t\t<minLodPixels>" << m_TileSize / 2 << "</minLodPixels>" << std::endl; + if (m_CurrentDepth == m_MaxDepth) fileTest << "\t\t\t\t<maxLodPixels>-1</maxLodPixels>" << std::endl; + else fileTest << "\t\t\t\t<maxLodPixels>" << m_TileSize * 2 << "</maxLodPixels>" << std::endl; + fileTest << "\t\t\t\t</Lod>" << std::endl; + fileTest << "\t\t\t\t<LatLonAltBox>" << std::endl; + fileTest << "\t\t\t\t\t<north>" << north << "</north>" << std::endl; + fileTest << "\t\t\t\t\t<south>" << centerLat << "</south>" << std::endl; + fileTest << "\t\t\t\t\t<east>" << centerLong << "</east>" << std::endl; + fileTest << "\t\t\t\t\t<west>" << west << "</west>" << std::endl; + fileTest << "\t\t\t\t</LatLonAltBox>" << std::endl; + fileTest << "\t\t\t</Region>" << std::endl; + fileTest << "\t\t\t<Link>" << std::endl; + fileTest << "\t\t\t\t<href>" << fileTile1.str() << ".kml</href>" << std::endl; + fileTest << "\t\t\t\t<viewRefreshMode>onRegion</viewRefreshMode>" << std::endl; + fileTest << "\t\t\t\t<viewFormat/>" << std::endl; + fileTest << "\t\t\t</Link>" << std::endl; + fileTest << "\t\t</NetworkLink>" << std::endl; + + /* Sous tuile 2 */ + std::ostringstream fileTile2; + fileTile2 << "../../"; + fileTile2 << depth + 1; + fileTile2 << "/"; + fileTile2 << tileStartX + 1; + fileTile2 << "/"; + fileTile2 << tileStartY; + + fileTest << "\t\t<NetworkLink>" << std::endl; + fileTest << "\t\t\t<name>" << fileTile2.str() << ".jpg</name>" << std::endl; + fileTest << "\t\t\t<Region>" << std::endl; + fileTest << "\t\t\t\t<Lod>" << std::endl; + fileTest << "\t\t\t\t\t<minLodPixels>" << m_TileSize / 2 << "</minLodPixels>" << std::endl; + if (m_CurrentDepth == m_MaxDepth) fileTest << "\t\t\t\t<maxLodPixels>-1</maxLodPixels>" << std::endl; + else fileTest << "\t\t\t\t<maxLodPixels>" << m_TileSize * 4 << "</maxLodPixels>" << std::endl; + fileTest << "\t\t\t\t</Lod>" << std::endl; + fileTest << "\t\t\t\t<LatLonAltBox>" << std::endl; + fileTest << "\t\t\t\t\t<north>" << north << "</north>" << std::endl; + fileTest << "\t\t\t\t\t<south>" << centerLat << "</south>" << std::endl; + fileTest << "\t\t\t\t\t<east>" << east << "</east>" << std::endl; + fileTest << "\t\t\t\t\t<west>" << centerLong << "</west>" << std::endl; + fileTest << "\t\t\t\t</LatLonAltBox>" << std::endl; + fileTest << "\t\t\t</Region>" << std::endl; + fileTest << "\t\t\t<Link>" << std::endl; + fileTest << "\t\t\t\t<href>" << fileTile2.str() << ".kml</href>" << std::endl; + fileTest << "\t\t\t\t<viewRefreshMode>onRegion</viewRefreshMode>" << std::endl; + fileTest << "\t\t\t\t<viewFormat/>" << std::endl; + fileTest << "\t\t\t</Link>" << std::endl; + fileTest << "\t\t</NetworkLink>" << std::endl; + + /* Sous tuile 3 */ + std::ostringstream fileTile3; + fileTile3 << "../../"; + fileTile3 << depth + 1; + fileTile3 << "/"; + fileTile3 << tileStartX + 1; + fileTile3 << "/"; + fileTile3 << tileStartY + 1; + + fileTest << "\t\t<NetworkLink>" << std::endl; + fileTest << "\t\t\t<name>" << fileTile3.str() << ".jpg</name>" << std::endl; + fileTest << "\t\t\t<Region>" << std::endl; + fileTest << "\t\t\t\t<Lod>" << std::endl; + fileTest << "\t\t\t\t\t<minLodPixels>" << m_TileSize / 2 << "</minLodPixels>" << std::endl; + if (m_CurrentDepth == m_MaxDepth) fileTest << "\t\t\t\t<maxLodPixels>-1</maxLodPixels>" << std::endl; + else fileTest << "\t\t\t\t<maxLodPixels>" << m_TileSize * 4 << "</maxLodPixels>" << std::endl; + fileTest << "\t\t\t\t</Lod>" << std::endl; + fileTest << "\t\t\t\t<LatLonAltBox>" << std::endl; + fileTest << "\t\t\t\t\t<north>" << centerLat << "</north>" << std::endl; + fileTest << "\t\t\t\t\t<south>" << south << "</south>" << std::endl; + fileTest << "\t\t\t\t\t<east>" << east << "</east>" << std::endl; + fileTest << "\t\t\t\t\t<west>" << centerLong << "</west>" << std::endl; + fileTest << "\t\t\t\t</LatLonAltBox>" << std::endl; + fileTest << "\t\t\t</Region>" << std::endl; + fileTest << "\t\t\t<Link>" << std::endl; + fileTest << "\t\t\t\t<href>" << fileTile3.str() << ".kml</href>" << std::endl; + fileTest << "\t\t\t\t<viewRefreshMode>onRegion</viewRefreshMode>" << std::endl; + fileTest << "\t\t\t\t<viewFormat/>" << std::endl; + fileTest << "\t\t\t</Link>" << std::endl; + fileTest << "\t\t</NetworkLink>" << std::endl; + + /* Sous tuile 4 */ + std::ostringstream fileTile4; + fileTile4 << "../../"; + fileTile4 << depth + 1; + fileTile4 << "/"; + fileTile4 << tileStartX; + fileTile4 << "/"; + fileTile4 << tileStartY + 1; + + fileTest << "\t\t<NetworkLink>" << std::endl; + fileTest << "\t\t\t<name>" << fileTile4.str() << ".jpg</name>" << std::endl; + fileTest << "\t\t\t<Region>" << std::endl; + fileTest << "\t\t\t\t<Lod>" << std::endl; + fileTest << "\t\t\t\t\t<minLodPixels>" << m_TileSize / 2 << "</minLodPixels>" << std::endl; + if (m_CurrentDepth == m_MaxDepth) fileTest << "\t\t\t\t<maxLodPixels>-1</maxLodPixels>" << std::endl; + else fileTest << "\t\t\t\t<maxLodPixels>" << m_TileSize * 4 << "</maxLodPixels>" << std::endl; + + fileTest << "\t\t\t\t</Lod>" << std::endl; + fileTest << "\t\t\t\t<LatLonAltBox>" << std::endl; + fileTest << "\t\t\t\t\t<north>" << centerLat << "</north>" << std::endl; + fileTest << "\t\t\t\t\t<south>" << south << "</south>" << std::endl; + fileTest << "\t\t\t\t\t<east>" << centerLong << "</east>" << std::endl; + fileTest << "\t\t\t\t\t<west>" << west << "</west>" << std::endl; + fileTest << "\t\t\t\t</LatLonAltBox>" << std::endl; + fileTest << "\t\t\t</Region>" << std::endl; + fileTest << "\t\t\t<Link>" << std::endl; + fileTest << "\t\t\t\t<href>" << fileTile4.str() << ".kml</href>" << std::endl; + fileTest << "\t\t\t\t<viewRefreshMode>onRegion</viewRefreshMode>" << std::endl; + fileTest << "\t\t\t\t<viewFormat/>" << std::endl; + fileTest << "\t\t\t</Link>" << std::endl; + fileTest << "\t\t</NetworkLink>" << std::endl; + + fileTest << "\t</Document>" << std::endl; + fileTest << "</kml>" << std::endl; + fileTest.close(); + +} + + +/** + */ +template <class TInputImage> +std::string +KmzProductWriter<TInputImage> +::GetCuttenFileName(std::string description, unsigned int idx) +{ + std::string currentImageName; + std::string tempName; + + itk::OStringStream oss; + oss << "tiles_" << idx; + tempName = oss.str(); + + // Replace all the blanks in the string + unsigned int i = 0; + while (i < tempName.length()) + { + if (tempName[i] != ' ') currentImageName += tempName[i]; + i++; + } + + return currentImageName; +} + +template <class TInputImage> +void +KmzProductWriter<TInputImage> +::PrintSelf(std::ostream& os, itk::Indent indent) const +{ + // Call the superclass implementation + Superclass::PrintSelf(os, indent); +} + +} +#endif diff --git a/Examples/IO/CMakeLists.txt b/Examples/IO/CMakeLists.txt index 7a2c37ad13..ea258ee64b 100644 --- a/Examples/IO/CMakeLists.txt +++ b/Examples/IO/CMakeLists.txt @@ -117,6 +117,9 @@ ENDIF( OTB_USE_CURL ) #ADD_EXECUTABLE(TransformReadWrite TransformReadWrite.cxx ) #TARGET_LINK_LIBRARIES(TransformReadWrite) +ADD_EXECUTABLE(ImageToKmzChain ImageToKmzChain.cxx) +TARGET_LINK_LIBRARIES(ImageToKmzChain OTBIO) + IF( NOT OTB_DISABLE_CXX_TESTING AND BUILD_TESTING ) @@ -166,6 +169,42 @@ ADD_TEST(ioTeDEMToImageGeneratorTest ${EXE_TESTS1} ${INPUTDATA}/DEM_srtm ) +# Testing the chain of creating a kmz from +# a non georeferenced image +ADD_TEST(ioImageToKmzChain ${EXE_TESTS1} + #--compare-image ${EPSILON_5} ${BASELINE}/DEMToImageGenerator.tif + # ${TEMP}/DEMToImageGenerator.tif + ImageToKmzChain + ${DATA}/Haiti1.jpeg + ${TEMP}/ioTeHaitiKmzProduct.kmz + 1980.000000 1986.000000 -72.351257 18.555075 0.000000 + 1963.000000 1944.000000 -72.352051 18.556946 0.000000 + 2078.000000 1566.000000 -72.346130 18.574358 0.000000 + 2154.000000 1430.000000 -72.342377 18.580441 0.000000 + 2432.000000 1408.000000 -72.328964 18.581335 0.000000 + 2558.000000 934.000000 -72.322571 18.602974 0.000000 + 3492.000000 1397.000000 -72.278343 18.580887 0.000000 + 2890.000000 1439.000000 -72.306908 18.579464 0.000000 + 2098.000000 2469.000000 -72.345741 18.532839 0.000000 + 1941.000000 2473.000000 -72.353317 18.532595 0.00000 + 1644.000000 2409.000000 -72.367691 18.535810 0.000000 + 1440.000000 2448.000000 -72.377457 18.534243 0.000000 + 687.000000 2005.000000 -72.413315 18.554974 0.000000 + 741.000000 2366.000000 -72.410934 18.538496 0.000000 + 855.000000 2802.000000 -72.405739 18.518456 0.000000 + 1936.000000 2855.000000 -72.353920 18.515240 0.000000 + 3338.000000 2824.000000 -72.286240 18.515160 0.000000 + 3715.000000 1772.000000 -72.267570 18.563681 0.000000 + 3676.000000 1580.000000 -72.269203 18.572529 0.000000 + 3395.000000 931.000000 -72.282402 18.602425 0.000000 + 3426.000000 856.000000 -72.280792 18.605862 0.000000 + 2822.000000 707.000000 -72.309692 18.613203 0.000000 + 1891.000000 360.000000 -72.354301 18.629776 0.000000 + 3989.000000 2639.000000 -72.255020 18.523664 0.000000 + 417.000000 2317.000000 -72.426552 18.540876 0.000000 + ) + + IF( OTB_USE_CURL ) ADD_TEST(ioTeTileMapImageIOExampleTest ${EXE_TESTS2} --compare-image ${HIGHTOL} ${BASELINE}/openStreetMap.png @@ -240,4 +279,6 @@ ENDIF(ITK_USE_REVIEW) ENDIF(OTB_USE_LIBLAS) + + ENDIF( NOT OTB_DISABLE_CXX_TESTING AND BUILD_TESTING ) diff --git a/Examples/IO/ImageToKmzChain.cxx b/Examples/IO/ImageToKmzChain.cxx new file mode 100644 index 0000000000..909aaf6efc --- /dev/null +++ b/Examples/IO/ImageToKmzChain.cxx @@ -0,0 +1,162 @@ +/*========================================================================= + + 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 +// +// This example demonstrates the use of the +// \doxygen{otb}{KmzProductWriter}. This filter is intended to +// produce Kmz file (Google Earth Readable). In this example we will +// use a file with no meta-data, use the +// \doxygen{otb}{GGCPToRPCSensorModelImageFilter} in order to +// approximate a rpc model, and then use our filter to produce a kmz +// file. +// Note that the \doxygen{otb}{KmzProductWriter} can only process +// inputs with a non empty keyword list. +// +// The first step toward the use of these filters is to include the +// proper header files: the one for the rpc sensor estimation filter and +// the one defining the procedure for creating kmz files. +// +// Software Guide : EndLatex + +#include "otbMacro.h" +#include "otbVectorImage.h" +#include "otbImageFileReader.h" + +// Software Guide : BeginCodeSnippet +#include "otbKmzProductWriter.h" +#include "otbGCPsToRPCSensorModelImageFilter.h" +// Software Guide : EndCodeSnippet +// + +int main(int argc, char* argv[]) +{ + + if (argc < 3) + { + std::cerr << "Usage: " << argv[0] << " infname outfname kmzFileName a1x a1y b1x b1y b1z ... aNx aNy aNz bNx bNy bNz" << std::endl; + return EXIT_FAILURE; + } + else if ((argc - 3) % 5 != 0) + { + std::cerr << "Inconsistent GCPs description!" << std::endl; + return EXIT_FAILURE; + } + + +// Software Guide : BeginLatex +// +// We will start by defining the types for the image and the image file +// reader. +// +// Software Guide : EndLatex +// Software Guide : BeginCodeSnippet + typedef otb::VectorImage<float, 2> ImageType; + typedef otb::ImageFileReader<ImageType> ReaderType; + + ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(argv[1]); +// Software Guide : EndCodeSnippet + +// Software Guide : BeginLatex +// +// We can now proceed to declare the type for the rpc sensor model +// estimation filter. The class \doxygen{otb}{GGCPToRPCSensorModelImageFilter} is +// templated over the input image type. +// +// Software Guide : EndLatex + +// Software Guide : BeginCodeSnippet + typedef otb::GCPsToRPCSensorModelImageFilter<ImageType> GCPsToSensorModelFilterType; + typedef GCPsToSensorModelFilterType::Point2DType Point2DType; + typedef GCPsToSensorModelFilterType::Point3DType Point3DType; + + GCPsToSensorModelFilterType::Pointer rpcEstimator = GCPsToSensorModelFilterType::New(); + rpcEstimator->SetInput(reader->GetOutput()); +// Software Guide : EndCodeSnippet + + unsigned int nbGCPs = (argc - 3) / 5; + + std::cout << "Receiving " << nbGCPs << " from command line." << std::endl; + + for (unsigned int gcpId = 0; gcpId < nbGCPs; ++gcpId) + { +// Software Guide : BeginLatex +// +// Here, we set all the Ground Control Points associated to the image +// indexes. This is the entry of the rpc sensor model +// estimator. Everytime a GCP is added, the output image information +// or its keywordlist is updated. In general, a dozen of GCPs are +// needed to estimate an accurate sensor model. The points are added +// via the method AddGCP(PointType2D, PointType3D). The outpput image +// obtained have the needed meta-data informations for the rest of the +// process. +// +// Software Guide : EndLatex + +// Software Guide : BeginCodeSnippet + Point2DType sensorPoint; + sensorPoint[0] = atof(argv[3 + gcpId * 5]); + sensorPoint[1] = atof(argv[4 + gcpId * 5]); + + Point3DType geoPoint; + geoPoint[0] = atof(argv[5 + 5 * gcpId]); + geoPoint[1] = atof(argv[6 + 5 * gcpId]); + geoPoint[2] = atof(argv[7 + 5 * gcpId]); + + rpcEstimator->AddGCP(sensorPoint, geoPoint); +// Software Guide : EndCodeSnippet + + std::cout << "Adding GCP sensor: " << sensorPoint << " <-> geo: " << geoPoint << std::endl; + } + + rpcEstimator->GetOutput()->UpdateOutputInformation(); + std::cout << "Residual ground error: " << rpcEstimator->GetRMSGroundError() << std::endl; + + +// Software Guide : BeginLatex +// +// The last step of the chain, is to export the image to a Google +// Earth understandable format using the KmzProductWriter. Note that +// the writer can associate legend via the method +// AddLegend(std::string description,ImageType * legend) and a logo +// SetLogo(ImageType*) to the kmz. +// +// Software Guide : EndLatex + +// Software Guide : BeginCodeSnippet + typedef otb::KmzProductWriter<ImageType> KmzProductWriterType; + KmzProductWriterType::Pointer kmzWriter = KmzProductWriterType::New(); +// Software Guide : EndCodeSnippet + +// Software Guide : BeginLatex +// +// Finally, we trigger the kmz writting by calling the \code{Update()} +// method on the writer. +// +// Software Guide : EndLatex + +// Software Guide : BeginCodeSnippet + kmzWriter->SetInput(rpcEstimator->GetOutput()); + kmzWriter->SetPath(argv[2]); + + kmzWriter->Update(); +// Software Guide : EndCodeSnippet + + return EXIT_SUCCESS; +} diff --git a/Examples/IO/otbIOExamplesTests1.cxx b/Examples/IO/otbIOExamplesTests1.cxx index 46e9ff85ea..e076a563cd 100644 --- a/Examples/IO/otbIOExamplesTests1.cxx +++ b/Examples/IO/otbIOExamplesTests1.cxx @@ -28,6 +28,8 @@ void RegisterTests() { REGISTER_TEST(ExtractROITest); REGISTER_TEST(DEMToImageGeneratorTest); + REGISTER_TEST(ImageToKmzChain); + } #undef main @@ -37,3 +39,7 @@ void RegisterTests() #undef main #define main DEMToImageGeneratorTest #include "DEMToImageGenerator.cxx" + +#undef main +#define main ImageToKmzChain +#include "ImageToKmzChain.cxx" diff --git a/Testing/Code/IO/CMakeLists.txt b/Testing/Code/IO/CMakeLists.txt index e21735c17e..50874e532d 100644 --- a/Testing/Code/IO/CMakeLists.txt +++ b/Testing/Code/IO/CMakeLists.txt @@ -2696,6 +2696,41 @@ ADD_TEST(ioTvMapFileProductWriter ${IO_TESTS21} 256 ) +ADD_TEST(ioTuKmzProductWriterNew ${IO_TESTS21} + otbKmzProductWriterNew +) + +ADD_TEST(ioTvKmzProductWriterWithGCP ${IO_TESTS21} + otbKmzProductWriter + ${INPUTDATA}/Haiti1.jpeg + ${TEMP}/ioTuHaitiKmzProduct.kmz + 1980.000000 1986.000000 -72.351257 18.555075 0.000000 + 1963.000000 1944.000000 -72.352051 18.556946 0.000000 + 2078.000000 1566.000000 -72.346130 18.574358 0.000000 + 2154.000000 1430.000000 -72.342377 18.580441 0.000000 + 2432.000000 1408.000000 -72.328964 18.581335 0.000000 + 2558.000000 934.000000 -72.322571 18.602974 0.000000 + 3492.000000 1397.000000 -72.278343 18.580887 0.000000 + 2890.000000 1439.000000 -72.306908 18.579464 0.000000 + 2098.000000 2469.000000 -72.345741 18.532839 0.000000 + 1941.000000 2473.000000 -72.353317 18.532595 0.00000 + 1644.000000 2409.000000 -72.367691 18.535810 0.000000 + 1440.000000 2448.000000 -72.377457 18.534243 0.000000 + 687.000000 2005.000000 -72.413315 18.554974 0.000000 + 741.000000 2366.000000 -72.410934 18.538496 0.000000 + 855.000000 2802.000000 -72.405739 18.518456 0.000000 + 1936.000000 2855.000000 -72.353920 18.515240 0.000000 + 3338.000000 2824.000000 -72.286240 18.515160 0.000000 + 3715.000000 1772.000000 -72.267570 18.563681 0.000000 + 3676.000000 1580.000000 -72.269203 18.572529 0.000000 + 3395.000000 931.000000 -72.282402 18.602425 0.000000 + 3426.000000 856.000000 -72.280792 18.605862 0.000000 + 2822.000000 707.000000 -72.309692 18.613203 0.000000 + 1891.000000 360.000000 -72.354301 18.629776 0.000000 + 3989.000000 2639.000000 -72.255020 18.523664 0.000000 + 417.000000 2317.000000 -72.426552 18.540876 0.000000 + ) + ADD_TEST(ioTuTileMapImageIOHelperNew ${IO_TESTS21} otbTileMapImageIOHelperNew ) @@ -2982,6 +3017,7 @@ SET(BasicIO_SRCS21 otbIOTests21.cxx otbMapFileProductWriterNew.cxx otbMapFileProductWriter.cxx +otbKmzProductWriter.cxx otbTileMapImageIOHelperTest.cxx otbComplexImageManipulationTest.cxx ) diff --git a/Testing/Code/IO/otbIOTests21.cxx b/Testing/Code/IO/otbIOTests21.cxx index 964dd2df95..84ce0b3b36 100644 --- a/Testing/Code/IO/otbIOTests21.cxx +++ b/Testing/Code/IO/otbIOTests21.cxx @@ -28,6 +28,8 @@ void RegisterTests() { REGISTER_TEST(otbMapFileProductWriterNew); REGISTER_TEST(otbMapFileProductWriter); + REGISTER_TEST(otbKmzProductWriterNew); + REGISTER_TEST(otbKmzProductWriter); REGISTER_TEST(otbTileMapImageIOHelperNew); REGISTER_TEST(otbTileMapImageIOHelperTest); // Complex tests diff --git a/Testing/Code/IO/otbKmzProductWriter.cxx b/Testing/Code/IO/otbKmzProductWriter.cxx new file mode 100644 index 0000000000..22a70c4419 --- /dev/null +++ b/Testing/Code/IO/otbKmzProductWriter.cxx @@ -0,0 +1,95 @@ +/*========================================================================= + + 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 "otbMacro.h" +#include "otbVectorImage.h" +#include "otbImageFileReader.h" +#include "otbKmzProductWriter.h" +#include "otbGCPsToRPCSensorModelImageFilter.h" + +typedef otb::VectorImage<float, 2> ImageType; +typedef otb::KmzProductWriter<ImageType> KmzProductWriterType; + +int otbKmzProductWriterNew(int argc, char* argv[]) +{ + KmzProductWriterType::Pointer kmzWriter = KmzProductWriterType::New(); + return EXIT_SUCCESS; +} + +int otbKmzProductWriter(int argc, char* argv[]) +{ + + if (argc < 3) + { + std::cerr << "Usage: " << argv[0] << " infname kmzFileName a1x a1y b1x b1y b1z ... aNx aNy aNz bNx bNy bNz" << std::endl; + return EXIT_FAILURE; + } + else if ((argc - 3) % 5 != 0) + { + std::cout <<"argc " << argc << std::endl; + std::cerr << "Inconsistent GCPs description!" << std::endl; + return EXIT_FAILURE; + } + + const char * infname = argv[1]; + const char * kmzFileName = argv[2]; + + typedef otb::ImageFileReader<ImageType> ReaderType; + typedef otb::GCPsToRPCSensorModelImageFilter<ImageType> GCPsToSensorModelFilterType; + typedef GCPsToSensorModelFilterType::Point2DType Point2DType; + typedef GCPsToSensorModelFilterType::Point3DType Point3DType; + + ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(infname); + + GCPsToSensorModelFilterType::Pointer rpcEstimator = GCPsToSensorModelFilterType::New(); + rpcEstimator->SetInput(reader->GetOutput()); + + unsigned int nbGCPs = (argc - 3) / 5; + + std::cout << "Receiving " << nbGCPs << " from command line." << std::endl; + + for (unsigned int gcpId = 0; gcpId < nbGCPs; ++gcpId) + { + Point2DType sensorPoint; + sensorPoint[0] = atof(argv[3 + gcpId * 5]); + sensorPoint[1] = atof(argv[4 + gcpId * 5]); + + Point3DType geoPoint; + geoPoint[0] = atof(argv[5 + 5 * gcpId]); + geoPoint[1] = atof(argv[6 + 5 * gcpId]); + geoPoint[2] = atof(argv[7 + 5 * gcpId]); + + std::cout << "Adding GCP sensor: " << sensorPoint << " <-> geo: " << geoPoint << std::endl; + + rpcEstimator->AddGCP(sensorPoint, geoPoint); + } + + rpcEstimator->GetOutput()->UpdateOutputInformation(); + + std::cout << "Residual ground error: " << rpcEstimator->GetRMSGroundError() << std::endl; + + // Second part : Image To Kmz + KmzProductWriterType::Pointer kmzWriter = KmzProductWriterType::New(); + + kmzWriter->SetInput(rpcEstimator->GetOutput()); + kmzWriter->SetPath(kmzFileName); + + kmzWriter->Update(); + + return EXIT_SUCCESS; +} -- GitLab