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();