diff --git a/CMakeLists.txt b/CMakeLists.txt index 6aa8f06130eb649d402ffbfb7abd11df3035f10c..6487a2b89d4525f1cc3c78ceeaa1594c10f5d038 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,10 @@ INCLUDE (${CMAKE_ROOT}/Modules/CMakeBackwardCompatibilityCXX.cmake) #----------------------------------------------------------------------------- # Configure Dart testing support. This should be done before any # MESSAGE(FATAL_ERROR ...) commands are invoked. + +OPTION(BUILD_TESTING "Build testing." OFF) +OPTION(BUILD_EXAMPLES "Build the Examples directory." OFF) + INCLUDE(${CMAKE_ROOT}/Modules/Dart.cmake) MARK_AS_ADVANCED(TCL_TCLSH DART_ROOT) ENABLE_TESTING() @@ -63,8 +67,6 @@ ENDIF(BUILD_TESTING) INCLUDE(CommonDefinitions) -OPTION(BUILD_TESTING "Build testing." OFF) -OPTION(BUILD_EXAMPLES "Build the Examples directory." OFF) #----------------------------------------------------------------------------- # Option to activate deprecated classes diff --git a/Code/Common/otbCommandLineArgumentParser.cxx b/Code/Common/otbCommandLineArgumentParser.cxx index 46a307578401b8bf7e3f4485c2ea51f8c29724bc..82d5951b270176df84a99bc58d3a2779899d847e 100644 --- a/Code/Common/otbCommandLineArgumentParser.cxx +++ b/Code/Common/otbCommandLineArgumentParser.cxx @@ -302,9 +302,18 @@ bool CommandLineArgumentParser::TryParseCommandLine(int argc, char *argv[], if (argv[i + 1] != NULL) { std::string strArgv = std::string(argv[i + 1]); - if (strArgv[0] == '-') + if (strArgv[0] == '-' ) { - goOnFlag = false; + // Test if the string is an argument or a real + if(!this->IsNumber(strArgv)) + { + goOnFlag = false; + } + else // If not an argument add it to the option list + { + outResult->AddParameter(m_OptionList[index].CommonName, strArgv); + ++i; + } } else { @@ -337,6 +346,28 @@ bool CommandLineArgumentParser::TryParseCommandLine(int argc, char *argv[], return true; } + +bool CommandLineArgumentParser::IsNumber(std::string text) +{ + if(text.empty()) + return false; + + // Don't test the sign (-) + unsigned int i = 1; + while (text[i]) + { + if( text[i] != '.' && text[i] != ',') + { + if(!isdigit(text[i])) + { + return false; + } + } + i++; + } + return true; +} + bool CommandLineArgumentParser::FindOption(const std::string& option, int& index) { //Look through the option list diff --git a/Code/Common/otbCommandLineArgumentParser.h b/Code/Common/otbCommandLineArgumentParser.h index d9694515338181f3c7b69e1610dd2f62b67ee661..ca0eb07a94e2f1a8f069dc38ff73160d68d08eb5 100644 --- a/Code/Common/otbCommandLineArgumentParser.h +++ b/Code/Common/otbCommandLineArgumentParser.h @@ -263,6 +263,7 @@ private: void PrintUsage(std::ostream& os) const; void PrintVersion(std::ostream& os) const; bool FindOption(const std::string&, int& index); + bool IsNumber(std::string text); /** Try processing a command line. Returns false if something breaks */ bool TryParseCommandLine(int argc, char *argv[], diff --git a/Code/IO/otbKmzProductWriter.h b/Code/IO/otbKmzProductWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..fb5419446edca8d09608af29a92befbc432c0807 --- /dev/null +++ b/Code/IO/otbKmzProductWriter.h @@ -0,0 +1,314 @@ +/*========================================================================= + + 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 Google Earth. The input + * must have metadata (a non empty keywordlist) + * + * The size of the tiles can be set via the method + * SetTileSize(unsigned int), the user can also specify the name of + * the output Kmz filename via SetPath(). + * + * + * + * \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 typename InputImageType::RegionType RegionType; + typedef unsigned char OutputPixelType; + typedef typename InputImageType::Pointer InputImagePointer; + 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; + + // std::pair description <-> legend (image) + typedef std::pair<std::string,InputImagePointer> LegendPairType; + typedef std::vector<LegendPairType> LegendVectorType; + + /** 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(); + } + + // Public method to Add Logo + itkSetMacro(Logo,InputImagePointer); + + // Public method to store the legend and their description in the + // legendVector + void AddLegend(std::string description, const InputImagePointer legend) + { + LegendPairType legendPair; + legendPair.first = description; + legendPair.second = legend; + m_LegendVector.push_back(legendPair); + } + // Method to add legend with empty description + void AddLegend(const InputImagePointer legend) + { + std::string emptyString =""; + this->AddLegend(emptyString,legend); + } + + // Set the size of the tiles to produce + itkSetMacro(TileSize,int); + +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 generate 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(); + + // Add Legends to the root kml + void AddLegendToRootKml(double north, double south, double east, double west); + + /** 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); + + /** Method to add logo if any */ + void AddLogo(); + + /** Method to add Legend if any */ + void ProcessLegends(); + + 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; + + // Logo + InputImagePointer m_Logo; + + // Vector used to store legend and description + LegendVectorType m_LegendVector; +}; + +} // 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 0000000000000000000000000000000000000000..6815bd665a61b27e2edb88b01eae9a3a49dfb3ae --- /dev/null +++ b/Code/IO/otbKmzProductWriter.txx @@ -0,0 +1,1459 @@ +/*========================================================================= + + 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()); + + // Do some checks, If no metadata nor projection ref available, + // input is not usable. + bool emptyProjRef = m_VectorImage->GetProjectionRef().empty(); + bool emptyKWL = m_VectorImage->GetImageKeywordlist().GetSize() == 0 ? true : false; + + if(emptyProjRef && emptyKWL) + { + itkExceptionMacro(<<"The input image have empty keyword list, please use an image with metadata informations"); + } + + // Continue processing + this->Initialize(); + this->AddLogo(); + this->Tiling(); +} + + +template <class TInputImage> +void +KmzProductWriter<TInputImage> +::Initialize() +{ + // Check that the right extension is given : expected .kmz */ + if (itksys::SystemTools::GetFilenameLastExtension(m_Path) != ".kmz") + { + itkExceptionMacro(<<itksys::SystemTools::GetFilenameLastExtension(m_Path) + <<" is a wrong Extension FileName : Expected .kmz"); + } + + // Decompose the filename, the full path + 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()); + +} + + /** + * Add Logo if any + * + */ +template <class TInputImage> +void +KmzProductWriter<TInputImage> +::AddLogo() +{ + // Logo + if(!m_Logo.IsNull()) + { + std::ostringstream logoFilename; + logoFilename << m_Path; + logoFilename << "/logo.jpeg"; + + ossimFilename cachingDir(m_Path); + cachingDir.createDirectory(); + + typename CastFilterType::Pointer castFiler = CastFilterType::New(); + castFiler->SetInput(m_Logo); + + m_VectorWriter = VectorWriterType::New(); + m_VectorWriter->SetFileName(logoFilename.str()); + m_VectorWriter->SetInput(castFiler->GetOutput()); + m_VectorWriter->Update(); + + // Add the logo to the kmz + itk::OStringStream logo_root_path_in_kmz; + logo_root_path_in_kmz << "logo.jpeg"; + + itk::OStringStream logo_absolut_path; + logo_absolut_path << logoFilename.str(); + + this->AddFileToKMZ(logo_absolut_path, logo_root_path_in_kmz); + + // Remove the logo file with stdio method :remove + if (remove(logo_absolut_path.str().c_str()) != 0) + { + itkExceptionMacro(<< "Error while deleting the file" << logo_absolut_path.str()); + } + } +} + +/** + * Add legend if any + */ +template <class TInputImage> +void +KmzProductWriter<TInputImage> +::ProcessLegends() +{ + for (unsigned int idx = 0; idx < m_LegendVector.size(); idx++) + { + std::ostringstream legendName; + legendName << m_Path; + legendName << "/legend_" << idx <<".jpeg"; + + InputImagePointer legend = m_LegendVector[idx].second; + typename CastFilterType::Pointer castFiler = CastFilterType::New(); + castFiler->SetInput(legend); + + m_VectorWriter = VectorWriterType::New(); + m_VectorWriter->SetFileName(legendName.str().c_str()); + m_VectorWriter->SetInput(castFiler->GetOutput()); + m_VectorWriter->Update(); + + // Add the legend to the kmz + itk::OStringStream legend_root_path_in_kmz; + legend_root_path_in_kmz << "legends/legend_" << idx << ".jpeg"; + + itk::OStringStream legend_absolut_path; + legend_absolut_path << legendName.str(); + + this->AddFileToKMZ(legend_absolut_path, legend_root_path_in_kmz); + + // Remove the legend file with stdio method :remove + if (remove(legend_absolut_path.str().c_str()) != 0) + { + itkExceptionMacro(<< "Error while deleting the file" << legend_absolut_path.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; + + 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); + + // Case of input image with size lower than the tileSize + // this case is illustrated with depth==0 and + // sampleRatioValue==1 + if(depth==0 && sampleRatioValue == 1) + { + m_VectorRescaleIntensityImageFilter->SetAutomaticInputMinMaxComputation(true); + } + else + { + 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"; + + // 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); + } + + // 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->ProcessLegends(); + + // 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_Logo.IsNull()) + { + 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; + + 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; + + 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); + + m_RootKmlFile << "\t\t</Document>" << std::endl; +} + +/** + * Add the bounding box kml + */ + +template <class TInputImage> +void +KmzProductWriter<TInputImage> +::BoundingBoxKmlProcess(double north, double south, double east, double west) +{ + // Create the bounding kml + this->GenerateBoundingKML(north, south, east, west); + + // Add the root kml in the kmz + std::ostringstream bound_in_kmz; + bound_in_kmz << "bounds/bound_0"<< m_KmlExtension; + std::ostringstream bound_absolute_path; + bound_absolute_path << m_Path << "/bound_0"<< m_KmlExtension; + + // Add the root file in the kmz + this->AddFileToKMZ(bound_absolute_path, bound_in_kmz); + + // Remove the bounding files with stdio method :remove + if (remove(bound_absolute_path.str().c_str()) != 0) + { + itkExceptionMacro(<< "Error while deleting the file" << bound_absolute_path.str()); + } +} + +/** + * Add the legends available + * + */ +template <class TInputImage> +void +KmzProductWriter<TInputImage> +::AddLegendToRootKml(double north, double south, double east, double west) +{ + double lat = (north + south) / 2.; + double lon = (east + west) / 2.; + + if (m_LegendVector.size() > 0) + { + m_RootKmlFile << "\t\t\t\t<Placemark>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t<name>Legend</name>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t<description>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t\t<![CDATA[ Legend of the product " << m_FileName << std::endl; + + for(unsigned int idx = 0; idx < m_LegendVector.size(); idx++) + m_RootKmlFile << "\t\t\t\t\t\t<img src=\"legends/legend_"<< idx <<".jpeg\" width=\"215\" height=\"175\" >"; + + m_RootKmlFile << "\t\t\t\t\t\t ]]>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t</description>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t<Point>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t\t<coordinates>" << lon << "," << lat << "</coordinates>" << std::endl; + m_RootKmlFile << "\t\t\t\t\t</Point>" << std::endl; + m_RootKmlFile << "\t\t\t\t</Placemark>" << 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> +void +KmzProductWriter<TInputImage> +::GenerateBoundingKML(double north, double south, double east, double west) +{ + std::ostringstream kmlname; + kmlname << m_Path; + kmlname << "/"; + kmlname << "bound_0" << m_KmlExtension; + 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> Bounding box of the product " << m_FileName<< "</name>" << + std::endl; + fileTest << "\t\t<open>1</open>" << std::endl; + fileTest << "\t\t<Placemark>" << std::endl; + fileTest << "\t\t\t<description>The bounding Box of the image</description>" << std::endl; + fileTest << "\t\t<LineString>" << std::endl; + fileTest << "\t\t\t<extrude>0</extrude>" << std::endl; + fileTest << "\t\t\t<tessellate>1</tessellate>" << std::endl; + fileTest << "\t\t\t<altitudeMode>clampedToGround</altitudeMode>" << std::endl; + fileTest << "\t\t\t<coordinates>" << std::endl; + + fileTest << "\t\t\t\t\t" << west << "," << north << std::endl; + fileTest << "\t\t\t\t\t" << east << "," << north << std::endl; + fileTest << "\t\t\t\t\t" << east << "," << south << std::endl; + fileTest << "\t\t\t\t\t" << west << "," << south << std::endl; + fileTest << "\t\t\t\t\t" << west << "," << north << std::endl; + + fileTest << "\t\t\t</coordinates>" << std::endl; + fileTest << "\t\t</LineString>" << std::endl; + fileTest << "\t\t</Placemark>" << 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/Code/IO/otbMapFileProductWriter.h b/Code/IO/otbMapFileProductWriter.h index 66ae6c2fa2feeca29dabcd4477e2e98f686bf190..3dcb388320738d15a427b4f72007b30b0def06ea 100644 --- a/Code/IO/otbMapFileProductWriter.h +++ b/Code/IO/otbMapFileProductWriter.h @@ -51,8 +51,7 @@ namespace otb * for mapservers, a tile index and finally the tiles. * This class allow the user to specify the cgi-bin used (SetCGIPath) * and the directory where to store the index shapefile and the tiles - * (SetShapeIndexPath) - * + * via SetShapeIndexPath method * * \ingroup IO * @@ -144,6 +143,9 @@ public: this->Write(); } + /** Macro to set the SRID we want to project Data in*/ + itkSetMacro(SRID,int); + protected: MapFileProductWriter(); virtual ~MapFileProductWriter(); @@ -213,7 +215,7 @@ private: std::ofstream m_File; - int m_SRID; + int m_SRID; }; diff --git a/Code/IO/otbMapFileProductWriter.txx b/Code/IO/otbMapFileProductWriter.txx index 9eb96b233181bb0b6604ff6bb5e956690c6f74d6..dc826192b4a422de6247a768886222ece66bed2f 100644 --- a/Code/IO/otbMapFileProductWriter.txx +++ b/Code/IO/otbMapFileProductWriter.txx @@ -407,7 +407,6 @@ MapFileProductWriter<TInputImage> // Write the IndexTile typename VectorDataFileWriterType::Pointer writer = VectorDataFileWriterType::New(); writer->SetFileName(m_IndexShapeFileName); - std::cout <<" ---> Writing the vectordata : "<<m_IndexShapeFileName << std::endl; writer->SetInput(m_VectorDataIndexTile); writer->Update(); @@ -536,7 +535,7 @@ MapFileProductWriter<TInputImage> m_File <<"\t\tMETADATA" << std::endl; m_File <<"\t\t 'wms_title' 'Level0'" << std::endl; m_File <<"\t\t \'wms_onlineresource\' \'"<<m_CGIPath<<"?map="<<m_FileName<<"&\'" << std::endl; - m_File <<"\t\t \'wms_srs\' \'EPSG:"<<m_SRID<<" EPSG:900913\'" << std::endl; // TODO : guess the EPSG used + m_File <<"\t\t \'wms_srs\' \'EPSG:"<<m_SRID<<" EPSG:900913\'" << std::endl; m_File <<"\t\tEND" << std::endl; m_File <<"\tEND" << std::endl; @@ -565,7 +564,9 @@ MapFileProductWriter<TInputImage> m_File <<"\t\t\tPROJECTION" << std::endl; m_File <<"\t\t\t \"init=epsg:"<<m_SRID<<"\"" << std::endl; m_File <<"\t\t\tEND" << std::endl; - m_File <<"\t\t#MINSCALE 250000" << std::endl; + m_File <<"\t\t#MINSCALE 250000" << std::endl; // TODO : problem with + // the MINSCALE AND + // MAXSCALE .. m_File <<"\tEND" << std::endl; } diff --git a/Code/ObjectDetection/otbDescriptorsListSampleGenerator.txx b/Code/ObjectDetection/otbDescriptorsListSampleGenerator.txx index c6220d522c788abffe62d3fc7cfcbe235c02d747..097ccdf67db3fedb47226c8ae2563493ecb24da4 100644 --- a/Code/ObjectDetection/otbDescriptorsListSampleGenerator.txx +++ b/Code/ObjectDetection/otbDescriptorsListSampleGenerator.txx @@ -283,9 +283,7 @@ template <class TInputImage, class TVectorData, class TFunctionType, class TList void PersistentDescriptorsListSampleGenerator<TInputImage,TVectorData,TFunctionType,TListSample,TLabelListSample> ::BeforeThreadedGenerateData() -{ - std::cout << this->GetInput()->GetBufferedRegion() << std::endl; -} +{} template <class TInputImage, class TVectorData, class TFunctionType, class TListSample, class TLabelListSample> diff --git a/Examples/IO/CMakeLists.txt b/Examples/IO/CMakeLists.txt index 7a2c37ad137acfc576157a7fc605cea1e72587da..d901b5518a91128a26f9cde4aa8822b65e059234 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(ImageToKmzAndMapFileProductExample ImageToKmzAndMapFileProductExample.cxx) +TARGET_LINK_LIBRARIES(ImageToKmzAndMapFileProductExample OTBIO) + IF( NOT OTB_DISABLE_CXX_TESTING AND BUILD_TESTING ) @@ -166,6 +169,43 @@ ADD_TEST(ioTeDEMToImageGeneratorTest ${EXE_TESTS1} ${INPUTDATA}/DEM_srtm ) +# Testing the chain of creating a kmz and MapFilefrom +# a non georeferenced image +ADD_TEST(ioImageToKmzAndMapFileProductExample ${EXE_TESTS1} + ImageToKmzAndMapFileProductExample + ${DATA}/Haiti1.jpeg + ${TEMP}/ioTeHaitiKmzProduct.kmz + ${TEMP}/mapserverExample/ioTeHaitiMapFileProduct.map + ${TEMP}/mapserverExample/shapeindex + http://localhost/cgi-bin/mapserv + 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 +280,6 @@ ENDIF(ITK_USE_REVIEW) ENDIF(OTB_USE_LIBLAS) + + ENDIF( NOT OTB_DISABLE_CXX_TESTING AND BUILD_TESTING ) diff --git a/Examples/IO/ImageToKmzAndMapFileProductExample.cxx b/Examples/IO/ImageToKmzAndMapFileProductExample.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c174ec6e402394f1bc6643170c8f0ca08422a38f --- /dev/null +++ b/Examples/IO/ImageToKmzAndMapFileProductExample.cxx @@ -0,0 +1,208 @@ +/*========================================================================= + + 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} and the +// \doxygen{otb}{MapFileProductWriter}. +// The first filter is intended to produce Kmz file (Google Earth +// Readable), and the second one is intended to produce map files +// callable through a WMS (Web Map Service) service. 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 filters to produce a kmz +// and MapFile products. +// Note that the \doxygen{otb}{KmzProductWriter} and the +// \doxygen{otb}{MapFileProductWriter} 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 and finally +// the header concerning the MapProduct writer. +// +// Software Guide : EndLatex + +#include "otbMacro.h" +#include "otbVectorImage.h" +#include "otbImageFileReader.h" + +// Software Guide : BeginCodeSnippet +#include "otbKmzProductWriter.h" +#include "otbMapFileProductWriter.h" +#include "otbGCPsToRPCSensorModelImageFilter.h" +// Software Guide : EndCodeSnippet +// + +int main(int argc, char* argv[]) +{ + + if (argc < 6) + { + 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 - 6) % 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 - 6) / 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[6 + gcpId * 5]); + sensorPoint[1] = atof(argv[7 + gcpId * 5]); + + Point3DType geoPoint; + geoPoint[0] = atof(argv[8 + 5 * gcpId]); + geoPoint[1] = atof(argv[9 + 5 * gcpId]); + geoPoint[2] = atof(argv[10+ 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 add legends via the method +// AddLegend(std::string description,ImageType * legend) and a logo in +// the kmz using SetLogo(ImageType*). +// +// 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 + +// Software Guide : BeginLatex +// +// The Mapfile is the heart of MapServer. It defines the relationships +// between objects, points MapServer (http://mapserver.org/) to where +// data are located and defines how things are to be drawn. The class +// \doxygen{otb}{MapFileProductWriter} allow producing the mapserver +// configuration file, the tiles to draw, and shapefiles descrining +// the tiles and where to find them. +// The Mapfile writer allow setting the complete path to the mapfile +// via SetFileName(std::string),the path where to store the tiles via +// the method SetShapeIndexPath() and finally the path to the cgi-bin +// to use via the method SetGCIPath(). +// +// +// Software Guide : EndLatex + +// Software Guide : BeginCodeSnippet + typedef otb::MapFileProductWriter<ImageType> MapFileProductWriterType; + MapFileProductWriterType::Pointer mapWriter = MapFileProductWriterType::New(); +// Software Guide : EndCodeSnippet + +// Software Guide : BeginLatex +// +// The user can also specify a Spatial Reference System Identifier +// (SRID) to choose his projection. In this example we choose WGS84 to +// project our datas in. The SRID relative to WGS84 is 4326. +// Finally, we trigger the MapFile writting by calling the +// \code{Update()} method on the writer. +// +// Software Guide : EndLatex + +// Software Guide : BeginCodeSnippet + mapWriter->SetInput(rpcEstimator->GetOutput()); + mapWriter->SetFileName(argv[3]); + mapWriter->SetShapeIndexPath(argv[4]); + mapWriter->SetCGIPath(argv[5]); + mapWriter->SetSRID(4326); + + mapWriter->Update(); +// Software Guide : EndCodeSnippet + + return EXIT_SUCCESS; +} diff --git a/Examples/IO/otbIOExamplesTests1.cxx b/Examples/IO/otbIOExamplesTests1.cxx index 46e9ff85ea4807109391cdcdc5a66caa526b1bcc..950df52c7ff0fab3817daf394519421084fabaa8 100644 --- a/Examples/IO/otbIOExamplesTests1.cxx +++ b/Examples/IO/otbIOExamplesTests1.cxx @@ -28,6 +28,7 @@ void RegisterTests() { REGISTER_TEST(ExtractROITest); REGISTER_TEST(DEMToImageGeneratorTest); + REGISTER_TEST(ImageToKmzAndMapFileProductExample); } #undef main @@ -37,3 +38,7 @@ void RegisterTests() #undef main #define main DEMToImageGeneratorTest #include "DEMToImageGenerator.cxx" + +#undef main +#define main ImageToKmzAndMapFileProductExample +#include "ImageToKmzAndMapFileProductExample.cxx" diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index 68047a4d5713771575c01663e8747223e629adfd..e78eb810e89b11ef5ddb0c3b0498e307ef3c2077 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -45,7 +45,25 @@ OTB-v.3.8.0 - Changes since version 3.6.0 (????/??/??) * Internal ITK: removed compilation of medical image formats library and associated ImageIO * Internal ITK: removed dependency on libtiff, libjpeg, libpng and zlib, now handled by gdal * Support for gcc-4.5 - + +* Bug fix: + * Monteverdi + * 0000216: Monteverdi viewer unable to display multi band images + * 0000193: Crash in vectorization module when the after the activation of the semi-automatic mode + * 0000195: unable to perform TSX calibration with the sar calibration module in monteverdi 1.4 + * 0000207: Vectorization module shift coordinates + * 0000202: Error message "otbSVMModel.txx:310 eps <= O" in the SVM classification module + * 0000194: error message opening dataset in monteverdi (development version) + * 0000200: Monteverdi -in option does not open viewer anymore + + * OTB-applications + * 0000213: Problem in denomination of otb process chain wrapped as qgis plugin + * 0000201: otbFastOrthoRectif switched back to double precision again + + * OTB-lib + * 0000192: Crappy support of gdal: GDALImageIO + + OTB-v.3.6.0 - Changes since version 3.4.0 (2010/10/07) ----------------------------------------- diff --git a/Testing/CMakeLists.txt b/Testing/CMakeLists.txt index 3fa520c7bd37a7cff699ed58983472387f8a872b..8319b041e0a3190463c082ece3d792354461ea6d 100644 --- a/Testing/CMakeLists.txt +++ b/Testing/CMakeLists.txt @@ -58,7 +58,7 @@ ELSE(OTB_BINARY_DIR) ENDMACRO(OTB_ADD_EXECUTABLE) # Find OTB and load its settings. - FIND_PACKAGE(OTB) + FIND_PACKAGE(OTB PATHS /usr/lib/otb) IF(OTB_FOUND) INCLUDE(${OTB_USE_FILE}) ADD_SUBDIRECTORY(Code) diff --git a/Testing/Code/Common/CMakeLists.txt b/Testing/Code/Common/CMakeLists.txt index 9630fc3714d515ffa323c91e629e4a349469e294..3154ff08827babd976f2e3c985c231dc9c57c0fb 100644 --- a/Testing/Code/Common/CMakeLists.txt +++ b/Testing/Code/Common/CMakeLists.txt @@ -83,7 +83,7 @@ ADD_TEST(coTuCmdLineArgParser_EmptyList ${COMMON_TESTS1} ADD_TEST(coTuCmdLineArgParser_List1Arg ${COMMON_TESTS1} otbTestCommandLineArgumentParserList - -image image.png -entier 150 -double 12.25 -deuxentiers 78 56 -doubles 1.0) + -image image.png -entier 150 -double 12.25 -deuxentiers 78 56 -doubles 1.0 2.5) ADD_TEST(coTuCmdLineArgParser_List2Arg ${COMMON_TESTS1} otbTestCommandLineArgumentParserList @@ -93,6 +93,11 @@ ADD_TEST(coTuCmdLineArgParser_List2ArgBis ${COMMON_TESTS1} otbTestCommandLineArgumentParserList -image image.png -entier 150 -double 12.25 -doubles 1.0 2.0 -deuxentiers 78 56 ) + +ADD_TEST(coTuCmdLineArgParser_List3ArgWithError ${COMMON_TESTS1} + otbTestCommandLineArgumentParserList + -image image.png -entier 150 -double 12.25 -deuxentiers 78 56 -doubles 1.0 2.5 -3.5) + #ADD_TEST(coTuCmdLineArgParserGUIDeuxEntiers_ExactNumberArg ${COMMON_TESTS1} # otbTestCommandLineArgumentParserGUI # -image image.png -entier 150 -double 12.25 -deuxentiers 78 56 ) diff --git a/Testing/Code/IO/CMakeLists.txt b/Testing/Code/IO/CMakeLists.txt index e21735c17e525fb6713c6ea4f7034faef9ec221a..f5162c580e9c02f053f2fb5d88b928dfd08430e9 100644 --- a/Testing/Code/IO/CMakeLists.txt +++ b/Testing/Code/IO/CMakeLists.txt @@ -2696,6 +2696,74 @@ 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(ioTvKmzProductWriterWithGCP ${IO_TESTS21} + otbKmzProductWriterWithLogoAndLegend + -in ${INPUTDATA}/Haiti1.jpeg + -lo ${INPUTDATA}/cnes.png + -le ${INPUTDATA}/otb_big.png + -kmz ${TEMP}/ioTuHaitiKmzProductWithLogoAndLegend.kmz + -gcp 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 +3050,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 964dd2df95be43dfd70482739ba55a295708b91d..6b72864a86a160daf78c84a3a9f06689dc178dce 100644 --- a/Testing/Code/IO/otbIOTests21.cxx +++ b/Testing/Code/IO/otbIOTests21.cxx @@ -28,8 +28,11 @@ void RegisterTests() { REGISTER_TEST(otbMapFileProductWriterNew); REGISTER_TEST(otbMapFileProductWriter); + REGISTER_TEST(otbKmzProductWriterNew); + REGISTER_TEST(otbKmzProductWriter); + REGISTER_TEST(otbKmzProductWriter); REGISTER_TEST(otbTileMapImageIOHelperNew); - REGISTER_TEST(otbTileMapImageIOHelperTest); + REGISTER_TEST(otbKmzProductWriterWithLogoAndLegend); // Complex tests REGISTER_TEST(otbImageDoubleToImageComplex); REGISTER_TEST(otbImageComplexToImageDouble); diff --git a/Testing/Code/IO/otbKmzProductWriter.cxx b/Testing/Code/IO/otbKmzProductWriter.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e12e47d624885582d2685814e193e0a1c7332f22 --- /dev/null +++ b/Testing/Code/IO/otbKmzProductWriter.cxx @@ -0,0 +1,208 @@ +/*========================================================================= + + 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" +#include "otbCommandLineArgumentParser.h" + + +typedef otb::VectorImage<float, 2> ImageType; +typedef otb::KmzProductWriter<ImageType> KmzProductWriterType; +typedef otb::ImageFileReader<ImageType> ReaderType; +typedef otb::GCPsToRPCSensorModelImageFilter<ImageType> GCPsToSensorModelFilterType; +typedef GCPsToSensorModelFilterType::Point2DType Point2DType; +typedef GCPsToSensorModelFilterType::Point3DType Point3DType; + + +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; + } + + // Get the cli arguments + const char * infname = argv[1]; + const char * kmzFileName = argv[2]; + + // Instanciate reader + 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; +} + + +int otbKmzProductWriterWithLogoAndLegend(int argc, char* argv[]) +{ + // Parse command line parameters + typedef otb::CommandLineArgumentParser ParserType; + ParserType::Pointer parser = ParserType::New(); + + parser->SetProgramDescription("Chain that Estimate a sensor model in order to export the input image to Google Earth understandable format Kmz"); + parser->AddInputImage(); + parser->AddOption("--OutputProductName", "Output Kmz product ", "-kmz", 1, true); + parser->AddOption("--LogoImage", "Output Kmz product ", "-lo", 1, false); + parser->AddOption("--LegendImage", "Output Kmz product ", "-le", 1, false); + parser->AddOptionNParams("--GroudControlPoints", + "Ground Control Points to estimate sensor model a1x a1y b1x b1y b1z ... aNx aNy aNz bNx bNy bNz", + "-gcp", true); + + typedef otb::CommandLineArgumentParseResult ParserResultType; + ParserResultType::Pointer parseResult = ParserResultType::New(); + + try + { + parser->ParseCommandLine(argc,argv,parseResult); + } + catch ( itk::ExceptionObject & err ) + { + std::string descriptionException = err.GetDescription(); + if (descriptionException.find("ParseCommandLine(): Help Parser") != std::string::npos) + { + return EXIT_SUCCESS; + } + if (descriptionException.find("ParseCommandLine(): Version Parser") != std::string::npos) + { + return EXIT_SUCCESS; + } + return EXIT_FAILURE; + } + + // Check if the number of gcp pairs point is consistent + unsigned int nbPoints = parseResult->GetNumberOfParameters("--GroudControlPoints"); + + if (nbPoints % 5 != 0) + { + std::cout <<"argc " << argc << std::endl; + std::cerr << "Inconsistent GCPs description!" << std::endl; + return EXIT_FAILURE; + } + + // Instanciate reader + ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(parseResult->GetInputImage()); + + GCPsToSensorModelFilterType::Pointer rpcEstimator = GCPsToSensorModelFilterType::New(); + rpcEstimator->SetInput(reader->GetOutput()); + + std::cout << "Receiving " << nbPoints << " from command line." << std::endl; + + unsigned int nbGCPs = nbPoints/5; + + for (unsigned int gcpId = 0; gcpId < nbGCPs; ++gcpId) + { + Point2DType sensorPoint; + sensorPoint[0] = atof(argv[3 + gcpId * 5]); + sensorPoint[1] = atof(argv[4 + gcpId * 5]); + + sensorPoint[0] = parseResult->GetParameterFloat("--GroudControlPoints", gcpId * 5); + sensorPoint[1] = parseResult->GetParameterFloat("--GroudControlPoints", 1 + gcpId * 5); + + Point3DType geoPoint; + geoPoint[0] = parseResult->GetParameterFloat("--GroudControlPoints", 2 + gcpId * 5); + geoPoint[1] = parseResult->GetParameterFloat("--GroudControlPoints", 3 + gcpId * 5); + geoPoint[2] = parseResult->GetParameterFloat("--GroudControlPoints", 4 + gcpId * 5); + + 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(parseResult->GetParameterString("--OutputProductName")); + + // Read the logo if any + if(parseResult->IsOptionPresent("--LogoImage")) + { + ReaderType::Pointer logoReader = ReaderType::New(); + logoReader->SetFileName(parseResult->GetParameterString("--LogoImage")); + logoReader->Update(); + kmzWriter->SetLogo(logoReader->GetOutput()); + } + // Read the legend if any + if(parseResult->IsOptionPresent("--LegendImage")) + { + ReaderType::Pointer legendReader = ReaderType::New(); + legendReader->SetFileName(parseResult->GetParameterString("--LegendImage")); + legendReader->Update(); + kmzWriter->AddLegend("Input Legend",legendReader->GetOutput()); + kmzWriter->AddLegend(legendReader->GetOutput()); + } + + // trigger the writing + kmzWriter->Update(); + + return EXIT_SUCCESS; +} diff --git a/Utilities/ITK/Code/Common/itkImageBase.txx b/Utilities/ITK/Code/Common/itkImageBase.txx index 7b08abe92d495bb6490c3898a015752eb3ceeeb1..d782caab07e79166a3da168d16c39de6ad9ea40f 100644 --- a/Utilities/ITK/Code/Common/itkImageBase.txx +++ b/Utilities/ITK/Code/Common/itkImageBase.txx @@ -285,7 +285,7 @@ ImageBase<VImageDimension> else { // Let us try to give a warning of this change in behavior. - itkWarningMacro(<<"Not executing UpdateOutputData due to zero pixel condition RequestedRegion:" + itkDebugMacro(<<"Not executing UpdateOutputData due to zero pixel condition RequestedRegion:" << this->GetRequestedRegion() << " BufferedRegion: " << this->GetBufferedRegion()); } #endif // !ITK_LEGACY_SILENT && !ITK_LEGACY_REMOVE