From d44d963a3005e39b62286ea4b281bb98f7aba4b0 Mon Sep 17 00:00:00 2001
From: Oliver Sander <sander@igpm.rwth-aachen.de>
Date: Fri, 12 Feb 2010 13:59:50 +0000
Subject: [PATCH] various fixes in
 derivativeOfDistanceSquaredWRTSecondArgument()

[[Imported from SVN: r5552]]
---
 src/unitvector.hh | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/src/unitvector.hh b/src/unitvector.hh
index ba3321fc..e583af79 100644
--- a/src/unitvector.hh
+++ b/src/unitvector.hh
@@ -20,6 +20,9 @@ public:
 
      /** \brief The exponention map */
     static UnitVector exp(const UnitVector& p, const TangentVector& v) {
+
+        assert( std::abs(p.data_*v) < 1e-7 );
+
         const double norm = v.two_norm();
         UnitVector result = p;
         result.data_ *= std::cos(norm);
@@ -37,8 +40,23 @@ public:
     Unlike the distance itself the squared distance is differentiable at zero
      */
     static EmbeddedTangentVector derivativeOfDistanceSquaredWRTSecondArgument(const UnitVector& a, const UnitVector& b) {
+        double x = a.data_ * b.data_;
+        const double eps = 1e-12;
+
         EmbeddedTangentVector result = a.data_;
-        result *= -2*std::acos(a.data_ * b.data_) / std::sqrt(1-(a.data_*b.data_)*(a.data_*b.data_));
+
+        if (x > 1-eps) {  // regular expression is unstable, use the series expansion instead
+            result *= -2 + 2*(x-1)/3 - 4/15*(x-1)*(x-1) + 4/35*(x-1)*(x-1)*(x-1);
+        } else {
+            result *= -2*std::acos(x) / std::sqrt(1-x*x);
+        }
+
+        // Project gradient onto the tangent plane at b in order to obtain the surface gradient
+        result.axpy(-1*(b.data_*result), b.data_);
+
+        // Gradient must be a tangent vector at b, in other words, orthogonal to it
+        assert( std::abs(b.data_ * result) < 1e-7);
+
         return result;
     }
 
-- 
GitLab