diff --git a/Modules/Adapters/OSSIMAdapters/include/otbSarSensorModelAdapter.h b/Modules/Adapters/OSSIMAdapters/include/otbSarSensorModelAdapter.h
index 692c1574fc7e12b390832546a43154411d6f5e7b..8a713883b6720d0dd9b8e0ce89c03ae924cd75c9 100644
--- a/Modules/Adapters/OSSIMAdapters/include/otbSarSensorModelAdapter.h
+++ b/Modules/Adapters/OSSIMAdapters/include/otbSarSensorModelAdapter.h
@@ -24,6 +24,7 @@
 #include <memory>
 
 #include "otbDEMHandler.h"
+#include "itkPoint.h"
 
 namespace ossimplugins
 {
@@ -62,6 +63,9 @@ public:
 
   typedef std::auto_ptr<ossimplugins::ossimSarSensorModel> InternalModelPointer;
 
+  using Point2DType = itk::Point<double,2>;
+  using Point3DType = itk::Point<double,3>;
+  
   /** Method for creation through the object factory. */
   itkNewMacro(Self);
 
@@ -80,6 +84,21 @@ public:
   /** Deburst metadata if possible and return lines to keep in image file */
   bool Deburst(std::vector<std::pair<unsigned long, unsigned long> > & lines);
 
+  /** Transform world point (lat,lon,hgt) to input image point
+  (col,row) and YZ frame */
+  bool WorldToLineSampleYZ(const Point3DType & inGeoPoint, Point2DType & cr, Point2DType & yz) const;
+
+  /** Transform world point (lat,lon,hgt) to input image point
+  (col,row) */
+  bool WorldToLineSample(const Point3DType & inGEoPOint, Point2DType & cr) const;
+
+/** Transform world point (lat,lon,hgt) to satellite position (x,y,z) and satellite velocity */
+  bool WorldToSatPositionAndVelocity(const Point3DType & inGeoPoint, Point3DType & satelitePosition,  
+				     Point3DType & sateliteVelocity) const;
+
+  /** Transform world point (lat,lon,hgt) to cartesian point (x,y,z) */
+  static bool WorldToCartesian(const Point3DType & inGeoPoint, Point3DType & outCartesianPoint);
+
   static bool ImageLineToDeburstLine(const std::vector<std::pair<unsigned long,unsigned long> >& lines, unsigned long imageLine, unsigned long & deburstLine);
 
   static void DeburstLineToImageLine(const std::vector<std::pair<unsigned long,unsigned long> >& lines, unsigned long deburstLine, unsigned long & imageLine);
diff --git a/Modules/Adapters/OSSIMAdapters/src/otbSarSensorModelAdapter.cxx b/Modules/Adapters/OSSIMAdapters/src/otbSarSensorModelAdapter.cxx
index 62d5203af5c4d7dc04f4b9a3d66706cef1fa084a..56bcfbca01f498b1f8cc020b5c8e839ebf809cbb 100644
--- a/Modules/Adapters/OSSIMAdapters/src/otbSarSensorModelAdapter.cxx
+++ b/Modules/Adapters/OSSIMAdapters/src/otbSarSensorModelAdapter.cxx
@@ -109,7 +109,112 @@ void SarSensorModelAdapter::DeburstLineToImageLine(const std::vector<std::pair<u
   ossimplugins::ossimSarSensorModel::deburstLineToImageLine(lines,deburstLine,imageLine);
 }
 
+bool SarSensorModelAdapter::WorldToLineSampleYZ(const Point3DType & inGeoPoint, Point2DType & cr, Point2DType & yz) const
+{
+  if(m_SensorModel.get() == ITK_NULLPTR)
+    {
+    return false;
+    }
+
+  ossimGpt inGpt;
+  inGpt.lon = inGeoPoint[0];
+  inGpt.lat = inGeoPoint[1];
+  inGpt.hgt = inGeoPoint[2];
+
+  ossimDpt outDpt;
+
+  double y(0.),z(0.);
+  m_SensorModel->worldToLineSampleYZ(inGpt,outDpt,y,z);
+
+  if(outDpt.isNan())
+    return false;
+
+  cr[0]=outDpt.x;
+  cr[1]=outDpt.y;
+  yz[0]=y;
+  yz[1]=z;
+
+  return true;
+}
 
+bool SarSensorModelAdapter::WorldToLineSample(const Point3DType & inGeoPoint, Point2DType & cr) const
+{
+  if(m_SensorModel.get() == ITK_NULLPTR)
+    {
+    return false;
+    }
+
+  ossimGpt inGpt;
+  inGpt.lon = inGeoPoint[0];
+  inGpt.lat = inGeoPoint[1];
+  inGpt.hgt = inGeoPoint[2];
+
+  ossimDpt outDpt;
+
+  m_SensorModel->worldToLineSample(inGpt,outDpt);
+
+  if(outDpt.isNan())
+    return false;
+
+  cr[0]=outDpt.x;
+  cr[1]=outDpt.y;
+
+  return true;
+}
+
+bool SarSensorModelAdapter::WorldToCartesian(const Point3DType & inGeoPoint, Point3DType & outCartesianPoint)
+{
+  ossimGpt inGpt;
+  inGpt.lon = inGeoPoint[0];
+  inGpt.lat = inGeoPoint[1];
+  inGpt.hgt = inGeoPoint[2];
+
+  ossimEcefPoint outCartesien(inGpt);
+  
+  if(outCartesien.isNan())
+    return false;
+
+  outCartesianPoint[0] = outCartesien.x();
+  outCartesianPoint[1] = outCartesien.y();
+  outCartesianPoint[2] = outCartesien.z();
+
+  return true;
+}
+  
+bool SarSensorModelAdapter::WorldToSatPositionAndVelocity(const Point3DType & inGeoPoint, 
+							  Point3DType & satelitePosition, 
+							  Point3DType & sateliteVelocity) const
+{
+  if(m_SensorModel.get() == ITK_NULLPTR)
+    {
+      return false;
+    }
+
+  ossimGpt inGpt;
+  inGpt.lon = inGeoPoint[0];
+  inGpt.lat = inGeoPoint[1];
+  inGpt.hgt = inGeoPoint[2];
+  
+  ossimplugins::ossimSarSensorModel::TimeType azimuthTime;
+  double rangeTime;
+  ossimEcefPoint sensorPos;
+  ossimEcefVector sensorVel;
+
+  const bool success = m_SensorModel->worldToAzimuthRangeTime(inGpt, azimuthTime, rangeTime,sensorPos,sensorVel);
+  
+  if(sensorPos.isNan() || !success)
+    return false;
+
+  satelitePosition[0] = sensorPos.x();
+  satelitePosition[1] = sensorPos.y();
+  satelitePosition[2] = sensorPos.z();
+
+  sateliteVelocity[0] = sensorVel.x();
+  sateliteVelocity[1] = sensorVel.y();
+  sateliteVelocity[2] = sensorVel.z();    
+
+  return true;
+}
 
 
 } // namespace otb
diff --git a/Modules/Adapters/OSSIMAdapters/test/CMakeLists.txt b/Modules/Adapters/OSSIMAdapters/test/CMakeLists.txt
index 54a7117fc93c342e11d0e77b2b5226c70c0104cc..8dadc14ff05f911b3fa0af4cca37e05592cecced 100644
--- a/Modules/Adapters/OSSIMAdapters/test/CMakeLists.txt
+++ b/Modules/Adapters/OSSIMAdapters/test/CMakeLists.txt
@@ -31,6 +31,7 @@ otbGeometricSarSensorModelAdapter.cxx
 otbPlatformPositionAdapter.cxx
 otbDEMHandlerTest.cxx
 otbRPCSolverAdapterTest.cxx
+otbSarSensorModelAdapterTest.cxx
 )
 
 add_executable(otbOSSIMAdaptersTestDriver ${OTBOSSIMAdaptersTests})
@@ -499,3 +500,8 @@ otb_add_test(NAME uaTvRPCSolverAdapterValidationTest COMMAND otbOSSIMAdaptersTes
   ${INPUTDATA}/DEM/egm96.grd
   )
 
+
+otb_add_test(NAME uaTvSarSensorModelAdapter COMMAND otbOSSIMAdaptersTestDriver
+  otbSarSensorModelAdapterTest
+  ${INPUTDATA}/s1a-iw1-slc-vh-amp_xt.geom
+  )
diff --git a/Modules/Adapters/OSSIMAdapters/test/otbOSSIMAdaptersTestDriver.cxx b/Modules/Adapters/OSSIMAdapters/test/otbOSSIMAdaptersTestDriver.cxx
index 911e57e671884e9bb003e399b605b6dfd3dacf29..5f7295d6dffdb208aafde1ab1326ecdd544bd24f 100644
--- a/Modules/Adapters/OSSIMAdapters/test/otbOSSIMAdaptersTestDriver.cxx
+++ b/Modules/Adapters/OSSIMAdapters/test/otbOSSIMAdaptersTestDriver.cxx
@@ -33,4 +33,5 @@ void RegisterTests()
   REGISTER_TEST(otbPlatformPositionComputeBaselineTest);
   REGISTER_TEST(otbDEMHandlerTest);
   REGISTER_TEST(otbRPCSolverAdapterTest);
+  REGISTER_TEST(otbSarSensorModelAdapterTest);
 }
diff --git a/Modules/Adapters/OSSIMAdapters/test/otbSarSensorModelAdapterTest.cxx b/Modules/Adapters/OSSIMAdapters/test/otbSarSensorModelAdapterTest.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..d48f10066193796158002b55aba127b464814ccc
--- /dev/null
+++ b/Modules/Adapters/OSSIMAdapters/test/otbSarSensorModelAdapterTest.cxx
@@ -0,0 +1,84 @@
+/*
+ * 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 <fstream>
+#include <iomanip>
+
+#include "otbSarSensorModelAdapter.h"
+#include "otbImageKeywordlist.h"
+
+
+int otbSarSensorModelAdapterTest(int itkNotUsed(argc), char* argv[])
+{
+  std::string infname = argv[1];
+
+  otb::SarSensorModelAdapter::Pointer sensorModel = otb::SarSensorModelAdapter::New();
+
+  auto kwl = otb::ReadGeometryFromGEOMFile(infname);
+
+  bool success = sensorModel->LoadState(kwl);
+
+  if(!success)
+    {
+    std::cerr<<"Could not LoadState() from keyword list read from"<<infname<<std::endl;
+    return EXIT_FAILURE;
+    }
+
+  std::vector<std::pair<unsigned long, unsigned long> > lines;
+  success = sensorModel->Deburst(lines);
+
+  if(!success)
+    {
+    std::cerr<<"Deburst() call failed."<<std::endl;
+    return EXIT_FAILURE;
+    }
+  
+
+  otb::ImageKeywordlist outKwl;
+  success = sensorModel->SaveState(outKwl);
+  if(!success)
+    {
+    std::cerr<<"SaveState() call failed."<<std::endl;
+    return EXIT_FAILURE;
+    }
+  
+
+  otb::SarSensorModelAdapter::Point2DType out1,out2;
+  otb::SarSensorModelAdapter::Point3DType in, out3, out4, out5;
+
+  // GCP 99 from input geom file
+  //support_data.geom.gcp[99].world_pt.hgt:  2.238244926818182e+02
+  //support_data.geom.gcp[99].world_pt.lat:  4.323458093295080e+01
+  //support_data.geom.gcp[99].world_pt.lon:  1.116316013091967e+00
+    
+  in[0] = 4.323458093295080e+01;
+  in[1] = 1.116316013091967e+00;
+  in[2] = 2.238244926818182e+02;
+
+  sensorModel->WorldToLineSample(in,out1);
+  sensorModel->WorldToLineSampleYZ(in,out1,out2);
+
+  sensorModel->WorldToCartesian(in, out5);
+  sensorModel->WorldToSatPositionAndVelocity(in,out3, out4);
+  
+  
+  return EXIT_SUCCESS;
+}
diff --git a/Modules/ThirdParty/OssimPlugins/include/ossim/ossimSarSensorModel.h b/Modules/ThirdParty/OssimPlugins/include/ossim/ossimSarSensorModel.h
index d76968ecf1929a8f8034e016c8b13fa2d2ff3bfb..542b29e6f8c65dd98cd919bcf0f363cc8072c193 100644
--- a/Modules/ThirdParty/OssimPlugins/include/ossim/ossimSarSensorModel.h
+++ b/Modules/ThirdParty/OssimPlugins/include/ossim/ossimSarSensorModel.h
@@ -238,13 +238,36 @@ public:
     * \param[in] worldPoint World point to geocode
     * \param[out] azimuthTime Estimated zero-doppler azimuth time
     * \param[out] rangeTime Estimated range time
+    * \param[out] interpSensorPos interpolated ECEF sensor position
+    * \param[out] interpSensorVel interpolated ECEF sensor velocity
     * \return True if success, false otherwise. In this case,
     * azimuthTime and rangeTime will not be modified.
     */
-   /*virtual*/ bool worldToAzimuthRangeTime(const ossimGpt& worldPt, TimeType & azimuthTime, double & rangeTime) const;
+   /*virtual*/ bool worldToAzimuthRangeTime(const ossimGpt& worldPt, TimeType & azimuthTime, double & rangeTime, ossimEcefPoint & interpSensorPos, ossimEcefVector & interpSensorVel) const;
 
-   // TODO: document me
-   /*virtual*/ void lineSampleToAzimuthRangeTime(const ossimDpt & imPt, TimeType & azimuthTime, double & rangeTime) const;
+   /**
+    * This method implement inverse sar geolocation similar to
+    * worldToLineSample, except that it also returns (y,z)
+    * coordinates, defined as follows:
+    * Let n = |sensorPos|,
+    * ps2 = scalar_product(sensorPos,worldPoint)
+    * d = distance(sensorPos,worldPoint)
+    *
+    * z = n - ps2/n
+    * y = sqrt(d*d - z*z)
+    * 
+    * sign of y is furher adapted to be inverted if sensor is left or
+    * right looking 
+    *
+    * \param[in] worldPoint World point to geocode
+    * \param[out] imPt Corresponding estimated image point
+    * \param[out] y 
+    * \param[out] z 
+    * \return True if success, false otherwise. In this case,
+    */
+   void worldToLineSampleYZ(const ossimGpt& worldPt, ossimDpt& imPt, double & y, double & z) const;
+   
+   void lineSampleToAzimuthRangeTime(const ossimDpt & imPt, TimeType & azimuthTime, double & rangeTime) const;
 
    // TODO: document me
    bool autovalidateInverseModelFromGCPs(const double & xtol = 1, const double & ytol = 1, const double azTimeTol = 500, const double &rangeTimeTo=0.0000000001) const;
@@ -419,7 +442,8 @@ protected:
    ProductType                                 theProductType; // GRD/SLC
    DurationType                                theAzimuthTimeOffset; // Offset computed
    double                                      theRangeTimeOffset; // Offset in seconds, computed
-
+   bool                                        theRightLookingFlag;
+   
    static const double C;
 
    static const unsigned int thePluginVersion; // version of the SarSensorModel plugin
diff --git a/Modules/ThirdParty/OssimPlugins/src/ossim/ossimSarSensorModel.cpp b/Modules/ThirdParty/OssimPlugins/src/ossim/ossimSarSensorModel.cpp
index ac695a2a4b790ebce7671fc7e27c62a954e91098..bb8903ad981a1857fbedf1311cf626138c5bd035 100644
--- a/Modules/ThirdParty/OssimPlugins/src/ossim/ossimSarSensorModel.cpp
+++ b/Modules/ThirdParty/OssimPlugins/src/ossim/ossimSarSensorModel.cpp
@@ -12,7 +12,7 @@
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- *
+ 
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
@@ -137,7 +137,8 @@ namespace ossimplugins
       theRangeResolution(0.),
       theBistaticCorrectionNeeded(false),
       theAzimuthTimeOffset(seconds(0)),
-      theRangeTimeOffset(0.)
+      theRangeTimeOffset(0.),
+      theRightLookingFlag(true)
       {}
 
    ossimSarSensorModel::GCPRecordType const&
@@ -220,7 +221,58 @@ namespace ossimplugins
       TimeType azimuthTime;
       double rangeTime;
 
-      const bool success = worldToAzimuthRangeTime(worldPt, azimuthTime, rangeTime);
+      ossimEcefPoint sensorPos;
+      ossimEcefVector sensorVel;
+
+      const bool success = worldToAzimuthRangeTime(worldPt, azimuthTime, rangeTime, sensorPos, sensorVel);
+
+      if(!success)
+      {
+         imPt.makeNan();
+         return;
+      }
+      // std::clog << "AzimuthTime: " << azimuthTime << "\n";
+      // std::clog << "RangeTime: " << rangeTime << "\n";
+      // std::clog << "GRD: " << isGRD() << "\n";
+
+      // Convert azimuth time to line
+      azimuthTimeToLine(azimuthTime,imPt.y);
+
+      if(isGRD())
+      {
+         // GRD case
+         double groundRange(0);
+         slantRangeToGroundRange(rangeTime*C/2,azimuthTime,groundRange);
+         // std::clog << "GroundRange: " << groundRange << "\n";
+         // std::clog << "TheRangeResolution: " << theRangeResolution << "\n";
+
+         // Eq 32 p. 31
+         // TODO: possible micro-optimization: precompute 1/theRangeResolution, and
+         // use *
+         imPt.x = groundRange/theRangeResolution;
+      }
+      else
+      {
+         // std::clog << "TheNearRangeTime: " << theNearRangeTime << "\n";
+         // std::clog << "TheRangeSamplingRate: " << theRangeSamplingRate << "\n";
+         // SLC case
+         // Eq 23 and 24 p. 28
+         imPt.x = (rangeTime - theNearRangeTime)*theRangeSamplingRate;
+      }
+   }
+
+void ossimSarSensorModel::worldToLineSampleYZ(const ossimGpt& worldPt, ossimDpt & imPt, double & y, double & z) const
+   {
+      // std::clog << "ossimSarSensorModel::worldToLineSample()\n";
+      assert(theRangeResolution>0&&"theRangeResolution is null.");
+
+      // First compute azimuth and range time
+      TimeType azimuthTime;
+      double rangeTime;
+      ossimEcefPoint sensorPos;
+      ossimEcefVector sensorVel;
+
+      const bool success = worldToAzimuthRangeTime(worldPt, azimuthTime, rangeTime,sensorPos,sensorVel);
 
       if(!success)
       {
@@ -255,9 +307,35 @@ namespace ossimplugins
          // Eq 23 and 24 p. 28
          imPt.x = (rangeTime - theNearRangeTime)*theRangeSamplingRate;
       }
+
+      // Now computes Y and Z
+      ossimEcefPoint inputPt(worldPt);
+      double NormeS = sqrt(sensorPos[0]*sensorPos[0] + sensorPos[1]*sensorPos[1] + sensorPos[2]*sensorPos[2]);  /* distance du radar */                                                                           
+      double PS2 = inputPt[0]*sensorPos[0] + inputPt[1]*sensorPos[1] + inputPt[2]*sensorPos[2];
+
+      // TODO check for small NormesS to avoid division by zero ?
+      // Should never happen ...
+      assert(NormesS>1e-6);
+      z = NormeS - PS2/NormeS;
+
+      double distance = sqrt((sensorPos[0]-inputPt[0])*(sensorPos[0]-inputPt[0]) + 
+                             (sensorPos[1]-inputPt[1])*(sensorPos[1]-inputPt[1]) + 
+                             (sensorPos[2]-inputPt[2])*(sensorPos[2]-inputPt[2]));  
+
+      y = sqrt(distance*distance - z*z);
+
+      // Check view side and change sign of Y accordingly
+      if ( (( sensorVel[0] * (sensorPos[1]* inputPt[2] - sensorPos[2]* inputPt[1]) +
+              sensorVel[1] * (sensorPos[2]* inputPt[0] - sensorPos[0]* inputPt[2]) +
+              sensorVel[2] * (sensorPos[0]* inputPt[1] - sensorPos[1]* inputPt[0])) > 0) ^ theRightLookingFlag )
+        {
+        y = -y;
+        }
    }
 
-   bool ossimSarSensorModel::worldToAzimuthRangeTime(const ossimGpt& worldPt, TimeType & azimuthTime, double & rangeTime) const
+
+
+bool ossimSarSensorModel::worldToAzimuthRangeTime(const ossimGpt& worldPt, TimeType & azimuthTime, double & rangeTime, ossimEcefPoint & interpSensorPos, ossimEcefVector & interpSensorVel) const
    {
       // std::clog << "ossimSarSensorModel::worldToAzimuthRangeTime()\n";
       // First convert lat/lon to ECEF
@@ -265,8 +343,6 @@ namespace ossimplugins
 
       // Compute zero doppler time
       TimeType interpTime;
-      ossimEcefPoint interpSensorPos;
-      ossimEcefVector interpSensorVel;
 
       const bool success = zeroDopplerLookup(inputPt,azimuthTime,interpSensorPos,interpSensorVel);
 
@@ -857,7 +933,9 @@ namespace ossimplugins
          double   estimatedRangeTime;
 
          // Estimate times
-         const bool s1 = this->worldToAzimuthRangeTime(gcpIt->worldPt,estimatedAzimuthTime,estimatedRangeTime);
+         ossimEcefPoint sensorPos;
+         ossimEcefVector sensorVel;
+         const bool s1 = this->worldToAzimuthRangeTime(gcpIt->worldPt,estimatedAzimuthTime,estimatedRangeTime,sensorPos, sensorVel);
          this->worldToLineSample(gcpIt->worldPt,estimatedImPt);
 
          const bool thisSuccess
@@ -964,8 +1042,10 @@ namespace ossimplugins
          TimeType estimatedAzimuthTime;
          double   estimatedRangeTime;
 
+         ossimEcefPoint sensorPos;
+         ossimEcefVector sensorVel;
          // Estimate times
-         const bool s1 = this->worldToAzimuthRangeTime(gcpIt->worldPt,estimatedAzimuthTime,estimatedRangeTime);
+         const bool s1 = this->worldToAzimuthRangeTime(gcpIt->worldPt,estimatedAzimuthTime,estimatedRangeTime, sensorPos, sensorVel);
 
          if(s1)
          {
@@ -985,8 +1065,11 @@ namespace ossimplugins
          TimeType estimatedAzimuthTime;
          double   estimatedRangeTime;
 
+         ossimEcefPoint sensorPos;
+         ossimEcefVector sensorVel;
+
          // Estimate times
-         const bool s1 = this->worldToAzimuthRangeTime(gcpIt->worldPt,estimatedAzimuthTime,estimatedRangeTime);
+         const bool s1 = this->worldToAzimuthRangeTime(gcpIt->worldPt,estimatedAzimuthTime,estimatedRangeTime, sensorPos, sensorVel);
 
          if(s1)
          {