diff --git a/Modules/Adapters/OSSIMAdapters/include/otbSarSensorModelAdapter.h b/Modules/Adapters/OSSIMAdapters/include/otbSarSensorModelAdapter.h index a9630c1d379f2789e88fc0b192301b38ab46714c..722facc4be7252f76d01fd6c69329e98e847a603 100644 --- a/Modules/Adapters/OSSIMAdapters/include/otbSarSensorModelAdapter.h +++ b/Modules/Adapters/OSSIMAdapters/include/otbSarSensorModelAdapter.h @@ -89,6 +89,11 @@ public: bool BurstExtraction(const unsigned int burst_index, std::pair<unsigned long,unsigned long> & lines, std::pair<unsigned long,unsigned long> & samples); + + /** Deburst metadata if possible and prepare the burst concatenation */ + bool DeburstAndConcatenate(std::vector<std::pair<unsigned long, unsigned long> > & linesBursts, + std::vector<std::pair<unsigned long,unsigned long> > & samplesBursts); + /** Transform world point (lat,lon,hgt) to input image point (col,row) and YZ frame */ diff --git a/Modules/Adapters/OSSIMAdapters/src/otbSarSensorModelAdapter.cxx b/Modules/Adapters/OSSIMAdapters/src/otbSarSensorModelAdapter.cxx index 75b9fb5c7720a6f1952ba6ef03454f0e3cb9c4de..3a2fc9f40d685c93c88ce50667e6aed56a74e02b 100644 --- a/Modules/Adapters/OSSIMAdapters/src/otbSarSensorModelAdapter.cxx +++ b/Modules/Adapters/OSSIMAdapters/src/otbSarSensorModelAdapter.cxx @@ -113,6 +113,17 @@ bool SarSensorModelAdapter::BurstExtraction(const unsigned int burst_index, return false; } +bool +SarSensorModelAdapter::DeburstAndConcatenate(std::vector<std::pair<unsigned long, unsigned long> > & linesBursts, + std::vector<std::pair<unsigned long,unsigned long> >& samplesBursts) +{ + if(m_SensorModel.get()) + { + return m_SensorModel->deburstAndConcatenate(linesBursts, samplesBursts); + } + + return false; +} bool SarSensorModelAdapter::ImageLineToDeburstLine(const std::vector<std::pair<unsigned long,unsigned long> >& lines, unsigned long imageLine, unsigned long & deburstLine) { diff --git a/Modules/Applications/AppSARCalibration/app/CMakeLists.txt b/Modules/Applications/AppSARCalibration/app/CMakeLists.txt index 8c3e3337e372276066ebe0f4105cb0c2fb19e18f..5e518e169a3da8497098a5a68716b8746f7d0312 100644 --- a/Modules/Applications/AppSARCalibration/app/CMakeLists.txt +++ b/Modules/Applications/AppSARCalibration/app/CMakeLists.txt @@ -32,3 +32,8 @@ otb_create_application( NAME SARBurstExtraction SOURCES otbSARBurstExtraction.cxx LINK_LIBRARIES ${${otb-module}_LIBRARIES}) + +otb_create_application( + NAME SARConcatenateBursts + SOURCES otbSARConcatenateBursts.cxx + LINK_LIBRARIES ${${otb-module}_LIBRARIES}) diff --git a/Modules/Applications/AppSARCalibration/app/otbSARConcatenateBursts.cxx b/Modules/Applications/AppSARCalibration/app/otbSARConcatenateBursts.cxx new file mode 100644 index 0000000000000000000000000000000000000000..5c3ddd2a87c40ff6734116858e91a1da6163655e --- /dev/null +++ b/Modules/Applications/AppSARCalibration/app/otbSARConcatenateBursts.cxx @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES) + * + * This file is part of Orfeo Toolbox + * + * https://www.orfeo-toolbox.org/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "otbWrapperApplication.h" +#include "otbWrapperApplicationFactory.h" + +#include "otbMultiChannelExtractROI.h" +#include "otbImageList.h" + +#include "otbSarConcatenateBurstsImageFilter.h" + +namespace otb +{ +namespace Wrapper +{ +class SARConcatenateBursts : public Application +{ +public: + /** Standard class typedefs. */ + typedef SARConcatenateBursts Self; + typedef Application Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + /** Standard macro */ + itkNewMacro(Self); + + itkTypeMacro(SARConcatenateBursts, otb::Application); + + typedef otb::ImageList<FloatVectorImageType> ImageListType; + typedef MultiChannelExtractROI<FloatVectorImageType::InternalPixelType, + FloatVectorImageType::InternalPixelType> ExtractROIFilterType; + typedef ObjectList<ExtractROIFilterType> ExtractROIFilterListType; + + typedef otb::SarConcatenateBurstsImageFilter<FloatVectorImageType> BurstFusionFilterType; + +private: + void DoInit() override + { + SetName("SARConcatenateBursts"); + SetDescription("Concatenate a list of Bursts to provide a whole SAR Deburst Image."); + + // Documentation + SetDocName("SAR Concatenate Bursts"); + SetDocLongDescription("This application performs a burst concatenation and provides a SAR Deburst Image. " + "It reads the input image list (single bursts) " + "and generates a whole SAR image with deburst operations."); + SetDocLimitations("Only Sentinel1 IW SLC products are supported for now."); + SetDocAuthors("OTB-Team"); + + AddDocTag(Tags::SAR); + AddDocTag("Concatenation"); + + AddParameter(ParameterType_InputImageList, "il", "Input bursts list"); + SetParameterDescription("il", "The list of bursts to concatenate."); + + AddParameter(ParameterType_InputImage, "insar", "Input Sentinel1 IW SLC Image (only metadata used)"); + SetParameterDescription("insar", "Raw Sentinel1 IW SLC image, or any extract of such made by OTB (geom file needed)."); + + AddParameter(ParameterType_OutputImage, "out", "Output Image"); + SetParameterDescription("out", "The concatenated and debursted output image."); + + AddRAMParameter(); + + // Doc example parameter settings + SetDocExampleParameterValue("in","s1_iw_slc.tif"); + SetDocExampleParameterValue("il", "Burst0.png Burst1.png"); + SetDocExampleParameterValue("out", "otbConcatenateBursts.tif"); + + SetOfficialDocLink(); + } + + void DoUpdateParameters() override + {} + + void DoExecute() override + { + // Instanciate filters + ExtractROIFilterListType::Pointer m_ExtractorList = ExtractROIFilterListType::New(); + ImageListType::Pointer m_ImageList = ImageListType::New(); + BurstFusionFilterType::Pointer fusionFilter = BurstFusionFilterType::New(); + + // Get the input complex image list + FloatVectorImageListType* inList = GetParameterImageList("il"); + // Get the input complex image + FloatVectorImageType* in = GetParameterImage("insar"); + in->UpdateOutputInformation(); + + std::vector<std::pair<unsigned long,unsigned long> > lines; + std::vector<std::pair<unsigned long,unsigned long> > samples; + + // Check number of inputs with number of bursts into SLC image (must be the same) + unsigned int nbBursts = 1; + try + { + nbBursts = std::stoi(in->GetImageKeywordlist().GetMetadataByKey("support_data.geom.bursts.number")); + } + catch( ... ) + { + // Throw an execption + throw std::runtime_error("Failed to retrieve bursts.number value from .geom file."); + } + + if (inList->Size() != nbBursts) + { + throw std::runtime_error("Failed to concatenate bursts. Some bursts are missing."); + } + + // Coniguration for fusion filter + fusionFilter->SetSLCImageKeyWorList(in->GetImageKeywordlist()); + fusionFilter->getDeburstLinesAndSamples(lines, samples); + + // Split each input burst to keep only interested region + for( unsigned int i=0; i<inList->Size(); i++ ) + { + FloatVectorImageType::Pointer vectIm = inList->GetNthElement(i); + vectIm->UpdateOutputInformation(); + + // Retrieve start and size for each burst + std::pair<unsigned long,unsigned long> line = lines.at(i); + std::pair<unsigned long,unsigned long> sample = samples.at(i); + unsigned long startL = line.first; + unsigned long startS = sample.first; + unsigned long sizeL = line.second - line.first + 1; + unsigned long sizeS = sample.second - sample.first + 1; + + ExtractROIFilterType::Pointer extractor = ExtractROIFilterType::New(); + extractor->SetInput(vectIm); + extractor->SetStartX(startS); + extractor->SetStartY(startL); + extractor->SetSizeX(sizeS); + extractor->SetSizeY(sizeL); + extractor->UpdateOutputInformation(); + + m_ExtractorList->PushBack( extractor ); + m_ImageList->PushBack( extractor->GetOutput() ); + + } + + BurstFusionFilterType::SizeType layout; + layout[0] = 1; + layout[1] = nbBursts; + fusionFilter->SetLayout(layout); + + for (unsigned int i=0; i<(layout[0]*layout[1]); i++) + { + fusionFilter->SetInput(i,m_ImageList->GetNthElement(i)); + } + + SetParameterOutputImage("out", fusionFilter->GetOutput()); + + RegisterPipeline(); + } + + +}; +} +} + +OTB_APPLICATION_EXPORT(otb::Wrapper::SARConcatenateBursts) diff --git a/Modules/Radiometry/SARCalibration/include/otbSarBurstExtractionImageFilter.hxx b/Modules/Radiometry/SARCalibration/include/otbSarBurstExtractionImageFilter.hxx index da63ad09dbcdb3a62b3cd9567b3331da5dc8b711..c90d0a4c089787133b6e967f5b7519a31c95ea4e 100644 --- a/Modules/Radiometry/SARCalibration/include/otbSarBurstExtractionImageFilter.hxx +++ b/Modules/Radiometry/SARCalibration/include/otbSarBurstExtractionImageFilter.hxx @@ -101,6 +101,9 @@ SarBurstExtractionImageFilter<TImage>::GenerateOutputInformation() newKwl.AddKey("support_data_number_samples", std::to_string(burstSize[0])); newKwl.AddKey("support_data_number_lines", std::to_string(burstSize[1])); + + newKwl.AddKey("number_samples", std::to_string(burstSize[0])); + newKwl.AddKey("number_lines", std::to_string(burstSize[1])); // Set new keyword list to output image outputPtr->SetImageKeywordList(newKwl); diff --git a/Modules/Radiometry/SARCalibration/include/otbSarConcatenateBurstsImageFilter.h b/Modules/Radiometry/SARCalibration/include/otbSarConcatenateBurstsImageFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..1b1e943871ac52423dc703e5623457cd36d7e889 --- /dev/null +++ b/Modules/Radiometry/SARCalibration/include/otbSarConcatenateBurstsImageFilter.h @@ -0,0 +1,118 @@ + /* + * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES) + * + * This file is part of Orfeo Toolbox + * + * https://www.orfeo-toolbox.org/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef otbSarConcatenateBurstsImageFilter_h +#define otbSarConcatenateBurstsImageFilter_h + +#include "itkImageToImageFilter.h" +#include "otbTileImageFilter.h" +#include "otbImageKeywordlist.h" + +namespace otb +{ +/** \class SarConcatenateBurstsImageFilter + * \brief This filter allows making a spatial mosaic from a set of bursts + * + * This filter derives from TileImagefilter and produces a spatial mosaic from a set of bursts + * from Sentinel-1 IW products . The layout parameter allows setting up of the images will + * be patched together: it is a 2D array containing the number of images in the horizontal + * direction and vertical direction respectively. + * + * Images can be set using the PushBackInput() or SetInput(unsigned + * int, Image *) methods. Please note that input images are supposed + * to be set in the lexicographical order. + * + * This filter does not support missing images: the number of input + * images must match exactly layout[0]*layout[1]. Additional + * consistency checks are that the number of components and spacing + * must be consistent for all images, and the size of the images must + * match with each others. + * + * Metadata are adapted in order to correspond to the contatenated SAR image. + * + * \ingroup SARCalibration + * \ingroup MultiThreaded + * + * \ingroup OTBImageManipulation + */ +template <class TImage> +class ITK_EXPORT SarConcatenateBurstsImageFilter : + public TileImageFilter<TImage> +{ +public: + /** Standard class typedef */ + typedef SarConcatenateBurstsImageFilter Self; + typedef TileImageFilter<TImage> Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + /** Helper typedefs */ + typedef TImage ImageType; + typedef typename ImageType::Pointer ImagePointerType; + typedef typename ImageType::SizeType SizeType; + typedef typename ImageType::RegionType RegionType; + + typedef std::pair<unsigned long, unsigned long> RecordType; + typedef std::vector<RecordType> LinesRecordVectorType; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(SarConcatenateBurstsImageFilter, TileImageFilter); + + // Setter + void SetSLCImageKeyWorList(ImageKeywordlist sarImageKWL); + + bool getDeburstLinesAndSamples(LinesRecordVectorType & linesRecord, LinesRecordVectorType & samplesRecord); + +protected: + /** Constructor */ + SarConcatenateBurstsImageFilter(); + + /** Destructor */ + ~SarConcatenateBurstsImageFilter() override; + + /** PrintSelf method */ + void PrintSelf(std::ostream& os, itk::Indent indent) const override; + + /** Generate input requested region method */ + void GenerateOutputInformation() override; + + +private: + SarConcatenateBurstsImageFilter(const Self &) = delete; + void operator =(const Self&) = delete; + + // SLC KeywordList + ImageKeywordlist m_SLCImageKWL; + + // Deburst SLC KeywordList + ImageKeywordlist m_DeburstSLCImageKWL; +}; + +} // end namespace itk + +#ifndef OTB_MANUAL_INSTANTIATION +#include "otbSarConcatenateBurstsImageFilter.hxx" +#endif + +#endif diff --git a/Modules/Radiometry/SARCalibration/include/otbSarConcatenateBurstsImageFilter.hxx b/Modules/Radiometry/SARCalibration/include/otbSarConcatenateBurstsImageFilter.hxx new file mode 100644 index 0000000000000000000000000000000000000000..47b03c117335e7b51a953ba92e0142e80c4cd386 --- /dev/null +++ b/Modules/Radiometry/SARCalibration/include/otbSarConcatenateBurstsImageFilter.hxx @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES) + * + * This file is part of Orfeo Toolbox + * + * https://www.orfeo-toolbox.org/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef otbSarConcatenateBurstsImageFilter_hxx +#define otbSarConcatenateBurstsImageFilter_hxx + +#include "otbSarConcatenateBurstsImageFilter.h" +#include "itkImageRegionIterator.h" +#include "otbSarSensorModelAdapter.h" + +namespace otb +{ +template <class TImage> +SarConcatenateBurstsImageFilter<TImage> +::SarConcatenateBurstsImageFilter() +{ +} + +template <class TImage> +SarConcatenateBurstsImageFilter<TImage> +::~SarConcatenateBurstsImageFilter() +{ +} + +template <class TImage> +void +SarConcatenateBurstsImageFilter<TImage> +::SetSLCImageKeyWorList(ImageKeywordlist sarImageKWL) +{ + // Check if sarImageKWL not NULL + assert(&sarImageKWL && "SAR Image Metadata don't exist."); + m_SLCImageKWL = sarImageKWL; +} + +template <class TImage> +bool +SarConcatenateBurstsImageFilter<TImage> +::getDeburstLinesAndSamples(LinesRecordVectorType & linesRecord, LinesRecordVectorType & samplesRecord) +{ + // Try to create a SarSensorModelAdapter + SarSensorModelAdapter::Pointer sarSensorModel = SarSensorModelAdapter::New(); + + bool loadOk = sarSensorModel->LoadState(m_SLCImageKWL); + + if(!loadOk || !sarSensorModel->IsValidSensorModel()) + itkExceptionMacro(<<"Input image does not contain a valid SAR sensor model."); + + // Try to call the deburstAndConcatenate function + bool deburstAndConcatenateOk = sarSensorModel->DeburstAndConcatenate(linesRecord, samplesRecord); + + if(!deburstAndConcatenateOk) + itkExceptionMacro(<<"Could not deburst or concatenate from input bursts"); + + // Export the new keywordlist + bool saveOk = sarSensorModel->SaveState(m_DeburstSLCImageKWL); + + if(!saveOk) + itkExceptionMacro(<<"Could not export deburst SAR sensor model to keyword list"); + + return true; +} + + +template <class TImage> +void +SarConcatenateBurstsImageFilter<TImage> +::PrintSelf(std::ostream& os, itk::Indent indent) const +{ + Superclass::PrintSelf(os,indent); +} + +template <class TImage> +void +SarConcatenateBurstsImageFilter<TImage> +::GenerateOutputInformation() +{ + // First, call superclass implementation + Superclass::GenerateOutputInformation(); + + // Output KeywordList + ImageType * outputPtr = this->GetOutput(); + + m_DeburstSLCImageKWL.AddKey("support_data_number_samples", std::to_string(this->GetOutput()-> + GetLargestPossibleRegion(). + GetSize()[0])); + m_DeburstSLCImageKWL.AddKey("support_data_number_lines", std::to_string(this->GetOutput()-> + GetLargestPossibleRegion(). + GetSize()[1])); + + m_DeburstSLCImageKWL.AddKey("number_samples", std::to_string(this->GetOutput()-> + GetLargestPossibleRegion(). + GetSize()[0])); + m_DeburstSLCImageKWL.AddKey("number_lines", std::to_string(this->GetOutput()-> + GetLargestPossibleRegion(). + GetSize()[1])); + + // Set new keyword list to output image + outputPtr->SetImageKeywordList(m_DeburstSLCImageKWL); +} + + +} // end namepsace otb + +#endif diff --git a/Modules/Radiometry/SARCalibration/include/otbSarDeburstImageFilter.hxx b/Modules/Radiometry/SARCalibration/include/otbSarDeburstImageFilter.hxx index e15425f09236a28391fdb72105a316d6caa09c3a..15da81a3a5feef5b8aaecc3a489b4ce2e717e899 100644 --- a/Modules/Radiometry/SARCalibration/include/otbSarDeburstImageFilter.hxx +++ b/Modules/Radiometry/SARCalibration/include/otbSarDeburstImageFilter.hxx @@ -146,6 +146,9 @@ SarDeburstImageFilter<TImage>::GenerateOutputInformation() newKwl.AddKey("support_data_number_samples", std::to_string(deburstSize[0])); newKwl.AddKey("support_data_number_lines", std::to_string(deburstSize[1])); + newKwl.AddKey("number_samples", std::to_string(deburstSize[0])); + newKwl.AddKey("number_lines", std::to_string(deburstSize[1])); + // Set new keyword list to output image outputPtr->SetImageKeywordList(newKwl); } diff --git a/Modules/ThirdParty/OssimPlugins/include/ossim/ossimSarSensorModel.h b/Modules/ThirdParty/OssimPlugins/include/ossim/ossimSarSensorModel.h index 990bb434c70dabea4fdd78a986cbc1a2a2232c76..8a989dec78fa132f3f20376748f13797b8edfec0 100644 --- a/Modules/ThirdParty/OssimPlugins/include/ossim/ossimSarSensorModel.h +++ b/Modules/ThirdParty/OssimPlugins/include/ossim/ossimSarSensorModel.h @@ -335,6 +335,24 @@ public: bool burstExtraction(const unsigned int burst_index, std::pair<unsigned long,unsigned long> & lines, std::pair<unsigned long,unsigned long> & samples); + /** + * This method will perform a deburst and concatenation operation, and return the + * vector of lines and the vector of samples to keep in the + * image file. The lines and samples represents start/size into each indepedent bursts. + * Note that the deburst operation has no effect if theBurstRecords + * contains a single burst. Otherwise it will merge burst together + * into a single burst, and update GCPs accordingly. + * \return true if the deburst operation succeeded. No changes is + * made to the object if the operation fails. + * \param lines A container for the lines ranges to keep in the + * deburst image. + * \param samples A container for the samples ranges to keep in the + * deburst image. + * \param lines A Boolean to indicate only valids samples are required. + */ + bool deburstAndConcatenate(std::vector<std::pair<unsigned long,unsigned long> >& linesBursts, + std::vector<std::pair<unsigned long,unsigned long> >& samplesBursts); + /** * Returns pointer to a new instance, copy of this. */ diff --git a/Modules/ThirdParty/OssimPlugins/src/ossim/ossimSarSensorModel.cpp b/Modules/ThirdParty/OssimPlugins/src/ossim/ossimSarSensorModel.cpp index 89a8e82b9592316deccdc7b4531d413051d1a31f..045798f75172d24127509948e9ad06f8ba9497f7 100644 --- a/Modules/ThirdParty/OssimPlugins/src/ossim/ossimSarSensorModel.cpp +++ b/Modules/ThirdParty/OssimPlugins/src/ossim/ossimSarSensorModel.cpp @@ -1685,6 +1685,194 @@ ossimSarSensorModel::burstExtraction(const unsigned int burst_index, return true; } +bool +ossimSarSensorModel::deburstAndConcatenate(std::vector<std::pair<unsigned long,unsigned long> >& linesBursts, + std::vector<std::pair<unsigned long,unsigned long> >& samplesBursts) +{ + if(theBurstRecords.empty()) + return false; + + // declare lines and samples + std::vector<std::pair<unsigned long,unsigned long> > lines; + std::pair<unsigned long,unsigned long> samples; + + // First, clear lines record + linesBursts.clear(); + samplesBursts.clear(); + + // Check the single burst record case + if(theBurstRecords.size() == 1) + { + linesBursts.push_back(std::make_pair(theBurstRecords.front().startLine,theBurstRecords.front().endLine)); + samplesBursts.push_back(std::make_pair(theBurstRecords.front().startLine,theBurstRecords.front().endLine)); + return false; + } + + + ///////// deburst operation //////// + // Process each burst + std::vector<BurstRecordType>::const_iterator it = theBurstRecords.begin(); + // Correct since we have at least 2 bursts records + std::vector<BurstRecordType>::const_iterator next = it+1; + std::vector<BurstRecordType>::const_iterator itend = theBurstRecords.end(); + + unsigned long currentStart = it->startLine; + TimeType deburstAzimuthStartTime = it->azimuthStartTime; + + unsigned long deburstEndLine = 0; + + samples = std::make_pair(it->startSample, it->endSample); + + // Store halfLineOverlapBegin/End + unsigned long halfLineOverlapBegin[theBurstRecords.size()]; + unsigned long halfLineOverlapEnd[theBurstRecords.size()]; + + halfLineOverlapBegin[0] = 0; + + unsigned int counterBegin = 1; + unsigned int counterEnd = 0; + + for(; next!= itend ;++it,++next) + { + DurationType timeOverlapEnd = (it->azimuthStopTime - next->azimuthStartTime); + + unsigned long overlapLength = timeOverlapEnd/theAzimuthTimeInterval; + + halfLineOverlapEnd[counterEnd] = overlapLength/2; + TimeType endTimeInNextBurst = it->azimuthStopTime-(halfLineOverlapEnd[counterEnd]-1)*theAzimuthTimeInterval; + + halfLineOverlapBegin[counterBegin] = std::floor(0.5+(endTimeInNextBurst-next->azimuthStartTime)/theAzimuthTimeInterval); + + unsigned long currentStop = it->endLine-halfLineOverlapEnd[counterEnd]; + + deburstEndLine+= currentStop - currentStart + 1; // +1 because currentStart/Stop are both valids + + lines.push_back(std::make_pair(currentStart,currentStop)); + + currentStart = next->startLine+halfLineOverlapBegin[counterBegin]; + + // Find the first and last valid sampleburst + if (it->startSample > samples.first) + { + samples.first = it->startSample; + } + if (it->endSample < samples.second) + { + samples.second = it->endSample; + } + + + ++counterBegin; + ++counterEnd; + } + + halfLineOverlapEnd[theBurstRecords.size() - 1] = 0; + + TimeType deburstAzimuthStopTime = it->azimuthStopTime; + deburstEndLine+=it->endLine - currentStart; + + lines.push_back(std::make_pair(currentStart,it->endLine)); + + if (it->startSample > samples.first) + { + samples.first = it->startSample; + } + if (it->endSample < samples.second) + { + samples.second = it->endSample; + } + + // Now, update other metadata accordingly + std::vector<GCPRecordType> deburstGCPs; + + // Now move GCPs + for(std::vector<GCPRecordType>::iterator gcpIt = theGCPRecords.begin(); gcpIt!=theGCPRecords.end();++gcpIt) + { + GCPRecordType currentGCP = *gcpIt; + unsigned long newLine=0; + + unsigned long gcpLine = std::floor(currentGCP.imPt.y+0.5); + unsigned long gcpSample = std::floor(currentGCP.imPt.x+0.5); + + // Be careful about fractional part of GCPs + double fractionalLines = currentGCP.imPt.y - gcpLine; + double fractionalSamples = currentGCP.imPt.x - gcpSample; + + bool linesOk = imageLineToDeburstLine(lines,gcpLine,newLine); + + // Gcp into valid samples + bool samplesOk = true; + unsigned long newSample = gcpSample; + + samplesOk = false; + if (gcpSample >= samples.first && gcpSample <= samples.second) + { + samplesOk = true; + newSample -= samples.first; // Offset with first valid sample + } + + if(linesOk && samplesOk) + { + currentGCP.imPt.y = newLine + fractionalLines; + currentGCP.imPt.x = newSample + fractionalSamples; + deburstGCPs.push_back(currentGCP); + } + } + + theGCPRecords.swap(deburstGCPs); + + ///// linesBursts and samplesBursts (into Burst geometry) ///// + std::vector<BurstRecordType>::const_iterator itBursts = theBurstRecords.begin(); + std::vector<std::pair<unsigned long,unsigned long> >::const_iterator itlines = lines.begin(); + + unsigned int counter = 0; + + for(; itBursts!= theBurstRecords.end() ;++itBursts) + { + unsigned long currentStart_L = halfLineOverlapBegin[counter]; + unsigned long currentStop_L = itBursts->endLine - itBursts->startLine - halfLineOverlapEnd[counter]; + linesBursts.push_back(std::make_pair(currentStart_L, currentStop_L)); + + unsigned long currentStart_S = 0; + unsigned long currentStop_S = samples.second-samples.first; + + if (itBursts->startSample < samples.first) + { + currentStart_S = samples.first - itBursts->startSample; + } + currentStop_S += currentStart_S; + + samplesBursts.push_back(std::make_pair(currentStart_S, currentStop_S)); + + ++counter; + } + + // Clear the previous burst records + theBurstRecords.clear(); + + // Create the single burst + BurstRecordType deburstBurst; + deburstBurst.startLine = 0; + deburstBurst.azimuthStartTime = deburstAzimuthStartTime; + deburstBurst.endLine = deburstEndLine; + deburstBurst.azimuthStopTime = deburstAzimuthStopTime; + deburstBurst.startSample = 0; + deburstBurst.endSample = samples.second - samples.first; + + theBurstRecords.push_back(deburstBurst); + + // Adapt general metadata : theNearRangeTime, first_time_line, last_time_line + redaptMedataAfterDeburst = true; + theFirstLineTime = deburstBurst.azimuthStartTime; + theLastLineTime = deburstBurst.azimuthStopTime; + + theNearRangeTime += samples.first*(1/theRangeSamplingRate); + + + return true; +} + + bool ossimSarSensorModel::imageLineToDeburstLine(const std::vector<std::pair<unsigned long,unsigned long> >& lines, unsigned long imageLine, unsigned long & deburstLine) { std::vector<std::pair<unsigned long,unsigned long> >::const_iterator vit = lines.begin();