From 81ca7b43a22cbff14803a8d090db315f6d98ec61 Mon Sep 17 00:00:00 2001
From: Luc Maisonobe <luc@orekit.org>
Date: Sat, 21 Mar 2015 15:53:39 +0100
Subject: [PATCH] Use inverse cubic interpolation when possible for inverse
 location.

---
 .../linesensor/SensorMeanPlaneCrossing.java   | 30 +++++++++++++++----
 1 file changed, 24 insertions(+), 6 deletions(-)

diff --git a/src/main/java/org/orekit/rugged/linesensor/SensorMeanPlaneCrossing.java b/src/main/java/org/orekit/rugged/linesensor/SensorMeanPlaneCrossing.java
index 0788527d..b6984f87 100644
--- a/src/main/java/org/orekit/rugged/linesensor/SensorMeanPlaneCrossing.java
+++ b/src/main/java/org/orekit/rugged/linesensor/SensorMeanPlaneCrossing.java
@@ -307,7 +307,8 @@ public class SensorMeanPlaneCrossing {
         // as we know the solution is improved in the second stage of inverse location.
         // We expect two or three evaluations only. Each new evaluation shows up quickly in
         // the performances as it involves frames conversions
-        final double[]  searchHistory = new double[maxEval];
+        final double[]               crossingLineHistory = new double[maxEval];
+        final DerivativeStructure[]  betaHistory         = new DerivativeStructure[maxEval];
         double crossingLine     = midLine;
         Transform bodyToInert   = midBodyToInert;
         Transform scToInert     = midScToInert;
@@ -315,19 +316,36 @@ public class SensorMeanPlaneCrossing {
         boolean atMax           = false;
         for (int i = 0; i < maxEval; ++i) {
 
-            searchHistory[i] = crossingLine;
+            crossingLineHistory[i] = crossingLine;
             final FieldVector3D<DerivativeStructure> targetDirection =
                     evaluateLine(crossingLine, targetPV, bodyToInert, scToInert);
-            final DerivativeStructure beta = FieldVector3D.angle(targetDirection, meanPlaneNormal);
+            betaHistory[i] = FieldVector3D.angle(targetDirection, meanPlaneNormal);
 
-            final double deltaL = (0.5 * FastMath.PI - beta.getValue()) / beta.getPartialDerivative(1);
+            final double deltaL;
+            if (i == 0) {
+                // simple Newton iteration
+                deltaL        = (0.5 * FastMath.PI - betaHistory[i].getValue()) / betaHistory[i].getPartialDerivative(1);
+                crossingLine += deltaL;
+            } else {
+                // inverse cubic iteration
+                final double a0    = betaHistory[i - 1].getValue() - 0.5 * FastMath.PI;
+                final double l0    = crossingLineHistory[i - 1];
+                final double d0    = betaHistory[i - 1].getPartialDerivative(1);
+                final double a1    = betaHistory[i].getValue()     - 0.5 * FastMath.PI;
+                final double l1    = crossingLineHistory[i];
+                final double d1    = betaHistory[i].getPartialDerivative(1);
+                final double a1Ma0 = a1 - a0;
+                crossingLine = ((l0 * (a1 - 3 * a0) - a0 * a1Ma0 / d0) * a1 * a1 +
+                                (l1 * (3 * a1 - a0) - a1 * a1Ma0 / d1) * a0 * a0
+                               ) / (a1Ma0 * a1Ma0 * a1Ma0);
+                deltaL = crossingLine - l1;
+            }
             if (FastMath.abs(deltaL) <= accuracy) {
                 // return immediately, without doing any additional evaluation!
                 return new CrossingResult(sensor.getDate(crossingLine), crossingLine, targetDirection);
             }
-            crossingLine += deltaL;
             for (int j = 0; j < i; ++j) {
-                if (FastMath.abs(crossingLine - searchHistory[j]) <= 1.0) {
+                if (FastMath.abs(crossingLine - crossingLineHistory[j]) <= 1.0) {
                     // rare case: we are stuck in a loop!
                     // switch to a more robust (but slower) algorithm in this case
                     return slowFind(targetPV, crossingLine);
-- 
GitLab