From 566e6ebfa776f2577e062657206ea5fb80df77a1 Mon Sep 17 00:00:00 2001
From: sesteves <sroesteves@gmail.com>
Date: Thu, 18 Aug 2016 16:03:42 +0100
Subject: [PATCH] Luc changes

---
 .../MultiLayerModel.java                      | 25 ++++++++-----------
 .../MultiLayerModelTest.java                  |  9 +++----
 2 files changed, 13 insertions(+), 21 deletions(-)

diff --git a/src/main/java/org/orekit/rugged/atmosphericrefraction/MultiLayerModel.java b/src/main/java/org/orekit/rugged/atmosphericrefraction/MultiLayerModel.java
index eab5eb1d..b1fe1539 100644
--- a/src/main/java/org/orekit/rugged/atmosphericrefraction/MultiLayerModel.java
+++ b/src/main/java/org/orekit/rugged/atmosphericrefraction/MultiLayerModel.java
@@ -78,30 +78,26 @@ public class MultiLayerModel implements AtmosphericRefraction {
         try {
 
             Vector3D pos = satPos;
-            Vector3D los = satLos;
-            Vector3D zenith = null;
+            Vector3D los = satLos.normalize();
             double previousRefractionIndex = -1;
             GeodeticPoint gp = ellipsoid.transform(satPos, ellipsoid.getBodyFrame(), null);
 
-            for(ConstantRefractionLayer refractionLayer : refractionLayers) {
+            for (ConstantRefractionLayer refractionLayer : refractionLayers) {
 
-                if(refractionLayer.getLowestAltitude() > gp.getAltitude()) {
+                if (refractionLayer.getLowestAltitude() > gp.getAltitude()) {
                     continue;
                 }
 
                 if (previousRefractionIndex > 0) {
 
-                    // get new los
-                    final double theta1 = FastMath.toRadians(Vector3D.angle(los, zenith));
-                    final double theta2 = FastMath.asin(previousRefractionIndex * FastMath.sin(theta1) /
-                            refractionLayer.getRefractionIndex());
+                    // get new los by applying Snell's law at atmosphere layers interfaces
+                    // we avoid computing sequences of inverse-trigo/trigo/inverse-trigo functions
+                    // we just use linear algebra and square roots, it is faster and more accurate
+                    final double n1On2 = previousRefractionIndex / refractionLayer.getRefractionIndex();
+                    final double k     = n1On2 * Vector3D.dotProduct(los, gp.getZenith());
+                    los = new Vector3D(n1On2, los,
+                                       -k - FastMath.sqrt(1 + k * k - n1On2 * n1On2), gp.getZenith());
 
-                    final double cosTheta1     = FastMath.cos(theta1);
-                    final double cosTheta2     = FastMath.cos(theta2);
-
-                    final double a = FastMath.sqrt((1 - cosTheta2 * cosTheta2) / (1 - cosTheta1 * cosTheta1));
-                    final double b = a * cosTheta1 - cosTheta2;
-                    los = new Vector3D(a, los, b, zenith);
                 }
 
                 if (rawIntersection.getAltitude() > refractionLayer.getLowestAltitude()) {
@@ -111,7 +107,6 @@ public class MultiLayerModel implements AtmosphericRefraction {
                 // get intersection point
                 pos = ellipsoid.pointAtAltitude(pos, los, refractionLayer.getLowestAltitude());
                 gp = ellipsoid.transform(pos, ellipsoid.getBodyFrame(), null);
-                zenith = gp.getZenith();
 
                 previousRefractionIndex = refractionLayer.getRefractionIndex();
             }
diff --git a/src/test/java/org/orekit/rugged/atmosphericrefraction/MultiLayerModelTest.java b/src/test/java/org/orekit/rugged/atmosphericrefraction/MultiLayerModelTest.java
index 41e45aa8..41742f72 100644
--- a/src/test/java/org/orekit/rugged/atmosphericrefraction/MultiLayerModelTest.java
+++ b/src/test/java/org/orekit/rugged/atmosphericrefraction/MultiLayerModelTest.java
@@ -25,11 +25,7 @@ import org.orekit.rugged.errors.RuggedException;
 import org.orekit.rugged.intersection.AbstractAlgorithmTest;
 import org.orekit.rugged.intersection.IntersectionAlgorithm;
 import org.orekit.rugged.intersection.duvenhage.DuvenhageAlgorithm;
-import org.orekit.rugged.intersection.duvenhage.MinMaxTreeTile;
-import org.orekit.rugged.intersection.duvenhage.MinMaxTreeTileFactory;
-import org.orekit.rugged.raster.Tile;
 import org.orekit.rugged.raster.TileUpdater;
-import org.orekit.rugged.raster.TilesCache;
 import org.orekit.rugged.utils.NormalizedGeodeticPoint;
 
 public class MultiLayerModelTest extends AbstractAlgorithmTest {
@@ -49,8 +45,9 @@ public class MultiLayerModelTest extends AbstractAlgorithmTest {
 
         double distance = Vector3D.distance(earth.transform(rawIntersection), earth.transform(correctedIntersection));
 
-        // with the current code, this check fails, the distance is about 800m instead of a couple meters
-        Assert.assertEquals(0.0, distance, 2.0);
+        // this is almost a Nadir observation (LOS deviates between 1.4 and 1.6 degrees from vertical)
+        // so the refraction correction is small
+        Assert.assertEquals(0.0553797, distance, 1.0e-6);
     }
 
     @Override
-- 
GitLab