diff --git a/core/src/main/java/org/orekit/rugged/api/Rugged.java b/core/src/main/java/org/orekit/rugged/api/Rugged.java
index 51b09ee1e4c3805e20e83dcfe6a3f0941576b1b0..059c3acbb1ce32dba76764e7e82d12ef1319ee6f 100644
--- a/core/src/main/java/org/orekit/rugged/api/Rugged.java
+++ b/core/src/main/java/org/orekit/rugged/api/Rugged.java
@@ -49,6 +49,7 @@ import org.orekit.rugged.intersection.IntersectionAlgorithm;
 import org.orekit.rugged.intersection.duvenhage.DuvenhageAlgorithm;
 import org.orekit.rugged.raster.TileUpdater;
 import org.orekit.rugged.utils.ExtendedEllipsoid;
+import org.orekit.rugged.utils.NormalizedGeodeticPoint;
 import org.orekit.rugged.utils.SpacecraftToObservedBody;
 import org.orekit.time.AbsoluteDate;
 import org.orekit.utils.AngularDerivativesFilter;
@@ -725,102 +726,23 @@ public class Rugged {
      */
     public GeodeticPoint[] directLocalization(final String sensorName, final double lineNumber)
         throws RuggedException {
-        try {
-
-            // compute the approximate transform between spacecraft and observed body
-            final LineSensor   sensor      = getLineSensor(sensorName);
-            final AbsoluteDate date        = sensor.getDate(lineNumber);
-            final Transform    scToInert   = scToBody.getScToInertial(date);
-            final Transform    inertToBody = scToBody.getInertialToBody(date);
-            final Transform    approximate = new Transform(date, scToInert, inertToBody);
-
-            final Vector3D spacecraftVelocity =
-                    scToInert.transformPVCoordinates(PVCoordinates.ZERO).getVelocity();
-
-            // compute localization of each pixel
-            final Vector3D pInert    = scToInert.transformPosition(sensor.getPosition());
-            final GeodeticPoint[] gp = new GeodeticPoint[sensor.getNbPixels()];
-            for (int i = 0; i < sensor.getNbPixels(); ++i) {
-
-                final Vector3D obsLInert = scToInert.transformVector(sensor.getLos(i));
-                final Vector3D lInert;
-                if (aberrationOfLightCorrection) {
-                    // apply aberration of light correction
-                    // as the spacecraft velocity is small with respect to speed of light,
-                    // we use classical velocity addition and not relativistic velocity addition
-                    // we look for a positive k such that: c * lInert + vsat = k * obsLInert
-                    // with lInert normalized
-                    final double a = obsLInert.getNormSq();
-                    final double b = -Vector3D.dotProduct(obsLInert, spacecraftVelocity);
-                    final double c = spacecraftVelocity.getNormSq() - Constants.SPEED_OF_LIGHT * Constants.SPEED_OF_LIGHT;
-                    final double s = FastMath.sqrt(b * b - a * c);
-                    final double k = (b > 0) ? -c / (s + b) : (s - b) / a;
-                    lInert = new Vector3D( k   / Constants.SPEED_OF_LIGHT, obsLInert,
-                                          -1.0 / Constants.SPEED_OF_LIGHT, spacecraftVelocity);
-                } else {
-                    // don't apply aberration of light correction
-                    lInert = obsLInert;
-                }
-
-                if (lightTimeCorrection) {
-                    // compute DEM intersection with light time correction
-                    final Vector3D  sP       = approximate.transformPosition(sensor.getPosition());
-                    final Vector3D  sL       = approximate.transformVector(sensor.getLos(i));
-                    final Vector3D  eP1      = ellipsoid.transform(ellipsoid.pointOnGround(sP, sL));
-                    final double    deltaT1  = eP1.distance(sP) / Constants.SPEED_OF_LIGHT;
-                    final Transform shifted1 = inertToBody.shiftedBy(-deltaT1);
-                    final GeodeticPoint gp1  = algorithm.intersection(ellipsoid,
-                                                                      shifted1.transformPosition(pInert),
-                                                                      shifted1.transformVector(lInert));
-
-                    final Vector3D  eP2      = ellipsoid.transform(gp1);
-                    final double    deltaT2  = eP2.distance(sP) / Constants.SPEED_OF_LIGHT;
-                    final Transform shifted2 = inertToBody.shiftedBy(-deltaT2);
-                    gp[i] = algorithm.refineIntersection(ellipsoid,
-                                                         shifted2.transformPosition(pInert),
-                                                         shifted2.transformVector(lInert),
-                                                         gp1);
-
-                } else {
-                    // compute DEM intersection without light time correction
-                    final Vector3D pBody = inertToBody.transformPosition(pInert);
-                    final Vector3D lBody = inertToBody.transformVector(lInert);
-                    gp[i] = algorithm.refineIntersection(ellipsoid, pBody, lBody,
-                                                         algorithm.intersection(ellipsoid, pBody, lBody));
-                }
-
-            }
-
-            return gp;
-
-        } catch (OrekitException oe) {
-            throw new RuggedException(oe, oe.getSpecifier(), oe.getParts());
-        }
-    }
-
-    /** Direct localization of a single line-of-sight.
-     * @param date date of the localization
-     * @param position pixel position in spacecraft frame
-     * @param los normalized line-of-sight in spacecraft frame
-     * @return ground position of all pixels of the specified sensor line
-     * @exception RuggedException if line cannot be localized, or sensor is unknown
-     */
-    public GeodeticPoint directLocalization(final AbsoluteDate date, final Vector3D position, final Vector3D los)
-        throws RuggedException {
-        try {
 
-            // compute the approximate transform between spacecraft and observed body
-            final Transform    scToInert   = scToBody.getScToInertial(date);
-            final Transform    inertToBody = scToBody.getInertialToBody(date);
-            final Transform    approximate = new Transform(date, scToInert, inertToBody);
+        // compute the approximate transform between spacecraft and observed body
+        final LineSensor   sensor      = getLineSensor(sensorName);
+        final AbsoluteDate date        = sensor.getDate(lineNumber);
+        final Transform    scToInert   = scToBody.getScToInertial(date);
+        final Transform    inertToBody = scToBody.getInertialToBody(date);
+        final Transform    approximate = new Transform(date, scToInert, inertToBody);
 
-            final Vector3D spacecraftVelocity =
-                    scToInert.transformPVCoordinates(PVCoordinates.ZERO).getVelocity();
+        final Vector3D spacecraftVelocity =
+                scToInert.transformPVCoordinates(PVCoordinates.ZERO).getVelocity();
 
-            // compute localization of specified pixel
-            final Vector3D pInert    = scToInert.transformPosition(position);
+        // compute localization of each pixel
+        final Vector3D pInert    = scToInert.transformPosition(sensor.getPosition());
+        final GeodeticPoint[] gp = new GeodeticPoint[sensor.getNbPixels()];
+        for (int i = 0; i < sensor.getNbPixels(); ++i) {
 
-            final Vector3D obsLInert = scToInert.transformVector(los);
+            final Vector3D obsLInert = scToInert.transformVector(sensor.getLos(i));
             final Vector3D lInert;
             if (aberrationOfLightCorrection) {
                 // apply aberration of light correction
@@ -842,34 +764,105 @@ public class Rugged {
 
             if (lightTimeCorrection) {
                 // compute DEM intersection with light time correction
-                final Vector3D  sP       = approximate.transformPosition(position);
-                final Vector3D  sL       = approximate.transformVector(los);
-                final Vector3D  eP1      = ellipsoid.transform(ellipsoid.pointOnGround(sP, sL));
+                final Vector3D  sP       = approximate.transformPosition(sensor.getPosition());
+                final Vector3D  sL       = approximate.transformVector(sensor.getLos(i));
+                final Vector3D  eP1      = ellipsoid.transform(ellipsoid.pointOnGround(sP, sL, 0.0));
                 final double    deltaT1  = eP1.distance(sP) / Constants.SPEED_OF_LIGHT;
                 final Transform shifted1 = inertToBody.shiftedBy(-deltaT1);
-                final GeodeticPoint gp1  = algorithm.intersection(ellipsoid,
-                                                                  shifted1.transformPosition(pInert),
-                                                                  shifted1.transformVector(lInert));
+                final NormalizedGeodeticPoint gp1  = algorithm.intersection(ellipsoid,
+                                                                            shifted1.transformPosition(pInert),
+                                                                            shifted1.transformVector(lInert));
 
                 final Vector3D  eP2      = ellipsoid.transform(gp1);
                 final double    deltaT2  = eP2.distance(sP) / Constants.SPEED_OF_LIGHT;
                 final Transform shifted2 = inertToBody.shiftedBy(-deltaT2);
-                return algorithm.refineIntersection(ellipsoid,
-                                                    shifted2.transformPosition(pInert),
-                                                    shifted2.transformVector(lInert),
-                                                    gp1);
+                gp[i] = algorithm.refineIntersection(ellipsoid,
+                                                     shifted2.transformPosition(pInert),
+                                                     shifted2.transformVector(lInert),
+                                                     gp1);
 
             } else {
                 // compute DEM intersection without light time correction
                 final Vector3D pBody = inertToBody.transformPosition(pInert);
                 final Vector3D lBody = inertToBody.transformVector(lInert);
-                return algorithm.refineIntersection(ellipsoid, pBody, lBody,
-                                                    algorithm.intersection(ellipsoid, pBody, lBody));
+                gp[i] = algorithm.refineIntersection(ellipsoid, pBody, lBody,
+                                                     algorithm.intersection(ellipsoid, pBody, lBody));
             }
 
-        } catch (OrekitException oe) {
-            throw new RuggedException(oe, oe.getSpecifier(), oe.getParts());
         }
+
+        return gp;
+
+    }
+
+    /** Direct localization of a single line-of-sight.
+     * @param date date of the localization
+     * @param position pixel position in spacecraft frame
+     * @param los normalized line-of-sight in spacecraft frame
+     * @return ground position of all pixels of the specified sensor line
+     * @exception RuggedException if line cannot be localized, or sensor is unknown
+     */
+    public GeodeticPoint directLocalization(final AbsoluteDate date, final Vector3D position, final Vector3D los)
+        throws RuggedException {
+
+        // compute the approximate transform between spacecraft and observed body
+        final Transform    scToInert   = scToBody.getScToInertial(date);
+        final Transform    inertToBody = scToBody.getInertialToBody(date);
+        final Transform    approximate = new Transform(date, scToInert, inertToBody);
+
+        final Vector3D spacecraftVelocity =
+                scToInert.transformPVCoordinates(PVCoordinates.ZERO).getVelocity();
+
+        // compute localization of specified pixel
+        final Vector3D pInert    = scToInert.transformPosition(position);
+
+        final Vector3D obsLInert = scToInert.transformVector(los);
+        final Vector3D lInert;
+        if (aberrationOfLightCorrection) {
+            // apply aberration of light correction
+            // as the spacecraft velocity is small with respect to speed of light,
+            // we use classical velocity addition and not relativistic velocity addition
+            // we look for a positive k such that: c * lInert + vsat = k * obsLInert
+            // with lInert normalized
+            final double a = obsLInert.getNormSq();
+            final double b = -Vector3D.dotProduct(obsLInert, spacecraftVelocity);
+            final double c = spacecraftVelocity.getNormSq() - Constants.SPEED_OF_LIGHT * Constants.SPEED_OF_LIGHT;
+            final double s = FastMath.sqrt(b * b - a * c);
+            final double k = (b > 0) ? -c / (s + b) : (s - b) / a;
+            lInert = new Vector3D( k   / Constants.SPEED_OF_LIGHT, obsLInert,
+                                   -1.0 / Constants.SPEED_OF_LIGHT, spacecraftVelocity);
+        } else {
+            // don't apply aberration of light correction
+            lInert = obsLInert;
+        }
+
+        if (lightTimeCorrection) {
+            // compute DEM intersection with light time correction
+            final Vector3D  sP       = approximate.transformPosition(position);
+            final Vector3D  sL       = approximate.transformVector(los);
+            final Vector3D  eP1      = ellipsoid.transform(ellipsoid.pointOnGround(sP, sL, 0.0));
+            final double    deltaT1  = eP1.distance(sP) / Constants.SPEED_OF_LIGHT;
+            final Transform shifted1 = inertToBody.shiftedBy(-deltaT1);
+            final NormalizedGeodeticPoint gp1  = algorithm.intersection(ellipsoid,
+                                                                        shifted1.transformPosition(pInert),
+                                                                        shifted1.transformVector(lInert));
+
+            final Vector3D  eP2      = ellipsoid.transform(gp1);
+            final double    deltaT2  = eP2.distance(sP) / Constants.SPEED_OF_LIGHT;
+            final Transform shifted2 = inertToBody.shiftedBy(-deltaT2);
+            return algorithm.refineIntersection(ellipsoid,
+                                                shifted2.transformPosition(pInert),
+                                                shifted2.transformVector(lInert),
+                                                gp1);
+
+        } else {
+            // compute DEM intersection without light time correction
+            final Vector3D pBody = inertToBody.transformPosition(pInert);
+            final Vector3D lBody = inertToBody.transformVector(lInert);
+            return algorithm.refineIntersection(ellipsoid, pBody, lBody,
+                                                algorithm.intersection(ellipsoid, pBody, lBody));
+        }
+
     }
 
     /** Find the date at which sensor sees a ground point.
diff --git a/core/src/main/java/org/orekit/rugged/intersection/BasicScanAlgorithm.java b/core/src/main/java/org/orekit/rugged/intersection/BasicScanAlgorithm.java
index fca8fa28ea46a7f10f3e29fa77035dfda086adfd..1082570d94a33240674fbf3a5b8d8ca91c0e8303 100644
--- a/core/src/main/java/org/orekit/rugged/intersection/BasicScanAlgorithm.java
+++ b/core/src/main/java/org/orekit/rugged/intersection/BasicScanAlgorithm.java
@@ -30,6 +30,7 @@ import org.orekit.rugged.raster.Tile;
 import org.orekit.rugged.raster.TileUpdater;
 import org.orekit.rugged.raster.TilesCache;
 import org.orekit.rugged.utils.ExtendedEllipsoid;
+import org.orekit.rugged.utils.NormalizedGeodeticPoint;
 
 /** Intersection computation using a basic algorithm based on exhaustive scan.
  * <p>
@@ -62,30 +63,37 @@ public class BasicScanAlgorithm implements IntersectionAlgorithm {
 
     /** {@inheritDoc} */
     @Override
-    public GeodeticPoint intersection(final ExtendedEllipsoid ellipsoid,
-                                      final Vector3D position, final Vector3D los)
+    public NormalizedGeodeticPoint intersection(final ExtendedEllipsoid ellipsoid,
+                                                final Vector3D position, final Vector3D los)
         throws RuggedException {
         try {
 
             // find the tiles between the entry and exit point in the Digital Elevation Model
-            GeodeticPoint entryPoint = null;
-            GeodeticPoint exitPoint  = null;
+            NormalizedGeodeticPoint entryPoint = null;
+            NormalizedGeodeticPoint exitPoint  = null;
             double minLatitude  = Double.NaN;
             double maxLatitude  = Double.NaN;
             double minLongitude = Double.NaN;
             double maxLongitude = Double.NaN;
             final List<SimpleTile> scannedTiles = new ArrayList<SimpleTile>();
+            double centralLongitude = Double.NaN;
             for (boolean changedMinMax = true; changedMinMax; changedMinMax = checkMinMax(scannedTiles)) {
 
                 scannedTiles.clear();
                 // compute entry and exit points
                 entryPoint = ellipsoid.transform(ellipsoid.pointAtAltitude(position, los, Double.isInfinite(hMax) ? 0.0 : hMax),
-                                                 ellipsoid.getBodyFrame(), null);
+                                                 ellipsoid.getBodyFrame(), null,
+                                                 Double.isNaN(centralLongitude) ? 0.0 : centralLongitude);
                 final SimpleTile entryTile = cache.getTile(entryPoint.getLatitude(), entryPoint.getLongitude());
+                if (Double.isNaN(centralLongitude)) {
+                    centralLongitude = entryTile.getMinimumLongitude();
+                    entryPoint = new NormalizedGeodeticPoint(entryPoint.getLatitude(), entryPoint.getLongitude(),
+                                                             entryPoint.getAltitude(), centralLongitude);
+                }
                 addIfNotPresent(scannedTiles, entryTile);
 
                 exitPoint = ellipsoid.transform(ellipsoid.pointAtAltitude(position, los, Double.isInfinite(hMin) ? 0.0 : hMin),
-                                                ellipsoid.getBodyFrame(), null);
+                                                ellipsoid.getBodyFrame(), null, centralLongitude);
                 final SimpleTile exitTile = cache.getTile(exitPoint.getLatitude(), exitPoint.getLongitude());
                 addIfNotPresent(scannedTiles, exitTile);
 
@@ -111,12 +119,12 @@ public class BasicScanAlgorithm implements IntersectionAlgorithm {
             }
 
             // scan the tiles
-            GeodeticPoint intersectionGP = null;
+            NormalizedGeodeticPoint intersectionGP = null;
             double intersectionDot = Double.POSITIVE_INFINITY;
             for (final SimpleTile tile : scannedTiles) {
                 for (int i = latitudeIndex(tile, minLatitude); i <= latitudeIndex(tile, maxLatitude); ++i) {
                     for (int j = longitudeIndex(tile, minLongitude); j <= longitudeIndex(tile, maxLongitude); ++j) {
-                        final GeodeticPoint gp = tile.pixelIntersection(entryPoint, ellipsoid.convertLos(entryPoint, los), i, j);
+                        final NormalizedGeodeticPoint gp = tile.pixelIntersection(entryPoint, ellipsoid.convertLos(entryPoint, los), i, j);
                         if (gp != null) {
 
                             // improve the point, by projecting it back on the 3D line, fixing the small body curvature at pixel level
@@ -124,7 +132,7 @@ public class BasicScanAlgorithm implements IntersectionAlgorithm {
                             final double        s         = Vector3D.dotProduct(delta, los) / los.getNormSq();
                             final GeodeticPoint projected = ellipsoid.transform(new Vector3D(1, position, s, los),
                                                                                 ellipsoid.getBodyFrame(), null);
-                            final GeodeticPoint gpImproved = tile.pixelIntersection(projected, ellipsoid.convertLos(projected, los), i, j);
+                            final NormalizedGeodeticPoint gpImproved = tile.pixelIntersection(projected, ellipsoid.convertLos(projected, los), i, j);
 
                             if (gpImproved != null) {
                                 final Vector3D point = ellipsoid.transform(gpImproved);
@@ -150,9 +158,9 @@ public class BasicScanAlgorithm implements IntersectionAlgorithm {
 
     /** {@inheritDoc} */
     @Override
-    public GeodeticPoint refineIntersection(final ExtendedEllipsoid ellipsoid,
-                                            final Vector3D position, final Vector3D los,
-                                            final GeodeticPoint closeGuess)
+    public NormalizedGeodeticPoint refineIntersection(final ExtendedEllipsoid ellipsoid,
+                                                      final Vector3D position, final Vector3D los,
+                                                      final NormalizedGeodeticPoint closeGuess)
         throws RuggedException {
         try {
             final Vector3D      delta     = ellipsoid.transform(closeGuess).subtract(position);
diff --git a/core/src/main/java/org/orekit/rugged/intersection/IgnoreDEMAlgorithm.java b/core/src/main/java/org/orekit/rugged/intersection/IgnoreDEMAlgorithm.java
index 06a6d3b3d596bdd3df054cc1d4bf1fa47d89dcbf..232fb2d92ee07704d0153293a06411d651e5f9ce 100644
--- a/core/src/main/java/org/orekit/rugged/intersection/IgnoreDEMAlgorithm.java
+++ b/core/src/main/java/org/orekit/rugged/intersection/IgnoreDEMAlgorithm.java
@@ -17,10 +17,9 @@
 package org.orekit.rugged.intersection;
 
 import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
-import org.orekit.bodies.GeodeticPoint;
-import org.orekit.errors.OrekitException;
 import org.orekit.rugged.api.RuggedException;
 import org.orekit.rugged.utils.ExtendedEllipsoid;
+import org.orekit.rugged.utils.NormalizedGeodeticPoint;
 
 /** Intersection ignoring Digital Elevation Model.
  * <p>
@@ -37,22 +36,17 @@ public class IgnoreDEMAlgorithm implements IntersectionAlgorithm {
 
     /** {@inheritDoc} */
     @Override
-    public GeodeticPoint intersection(final ExtendedEllipsoid ellipsoid,
-                                      final Vector3D position, final Vector3D los)
+    public NormalizedGeodeticPoint intersection(final ExtendedEllipsoid ellipsoid,
+                                                final Vector3D position, final Vector3D los)
         throws RuggedException {
-        try {
-            return ellipsoid.pointOnGround(position, los);
-        } catch (OrekitException oe) {
-            // this should never happen
-            throw new RuggedException(oe, oe.getSpecifier(), oe.getParts());
-        }
+        return ellipsoid.pointOnGround(position, los, 0.0);
     }
 
     /** {@inheritDoc} */
     @Override
-    public GeodeticPoint refineIntersection(final ExtendedEllipsoid ellipsoid,
-                                            final Vector3D position, final Vector3D los,
-                                            final GeodeticPoint closeGuess)
+    public NormalizedGeodeticPoint refineIntersection(final ExtendedEllipsoid ellipsoid,
+                                                      final Vector3D position, final Vector3D los,
+                                                      final NormalizedGeodeticPoint closeGuess)
         throws RuggedException {
         return intersection(ellipsoid, position, los);
     }
diff --git a/core/src/main/java/org/orekit/rugged/intersection/IntersectionAlgorithm.java b/core/src/main/java/org/orekit/rugged/intersection/IntersectionAlgorithm.java
index be93c8f0591242e7ebc59a2caef466b546e7f286..074bcca929c68f2e83d22ce4a42e52cf1057e541 100644
--- a/core/src/main/java/org/orekit/rugged/intersection/IntersectionAlgorithm.java
+++ b/core/src/main/java/org/orekit/rugged/intersection/IntersectionAlgorithm.java
@@ -20,6 +20,7 @@ import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
 import org.orekit.bodies.GeodeticPoint;
 import org.orekit.rugged.api.RuggedException;
 import org.orekit.rugged.utils.ExtendedEllipsoid;
+import org.orekit.rugged.utils.NormalizedGeodeticPoint;
 
 /** Interface for Digital Elevation Model intersection algorithm.
  * @author Luc Maisonobe
@@ -33,7 +34,7 @@ public interface IntersectionAlgorithm {
      * @return point at which the line first enters ground
      * @exception RuggedException if intersection cannot be found
      */
-    GeodeticPoint intersection(ExtendedEllipsoid ellipsoid, Vector3D position, Vector3D los)
+    NormalizedGeodeticPoint intersection(ExtendedEllipsoid ellipsoid, Vector3D position, Vector3D los)
         throws RuggedException;
 
     /** Refine intersection of line with Digital Elevation Model.
@@ -51,8 +52,8 @@ public interface IntersectionAlgorithm {
      * @return point at which the line first enters ground
      * @exception RuggedException if intersection cannot be found
      */
-    GeodeticPoint refineIntersection(ExtendedEllipsoid ellipsoid, Vector3D position, Vector3D los,
-                                     GeodeticPoint closeGuess)
+    NormalizedGeodeticPoint refineIntersection(ExtendedEllipsoid ellipsoid, Vector3D position, Vector3D los,
+                                               NormalizedGeodeticPoint closeGuess)
         throws RuggedException;
 
     /** Get elevation at a given ground point.
diff --git a/core/src/main/java/org/orekit/rugged/intersection/duvenhage/DuvenhageAlgorithm.java b/core/src/main/java/org/orekit/rugged/intersection/duvenhage/DuvenhageAlgorithm.java
index d390dab1cee07bb9864337cc2bc764d8b91b6fe3..824e55f17667306c554de1e829570229d4a4b2d4 100644
--- a/core/src/main/java/org/orekit/rugged/intersection/duvenhage/DuvenhageAlgorithm.java
+++ b/core/src/main/java/org/orekit/rugged/intersection/duvenhage/DuvenhageAlgorithm.java
@@ -18,7 +18,6 @@ package org.orekit.rugged.intersection.duvenhage;
 
 import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
 import org.apache.commons.math3.util.FastMath;
-import org.apache.commons.math3.util.MathUtils;
 import org.orekit.bodies.GeodeticPoint;
 import org.orekit.errors.OrekitException;
 import org.orekit.rugged.api.RuggedException;
@@ -28,6 +27,7 @@ import org.orekit.rugged.raster.Tile;
 import org.orekit.rugged.raster.TileUpdater;
 import org.orekit.rugged.raster.TilesCache;
 import org.orekit.rugged.utils.ExtendedEllipsoid;
+import org.orekit.rugged.utils.NormalizedGeodeticPoint;
 
 /** Digital Elevation Model intersection using Bernardt Duvenhage's algorithm.
  * <p>
@@ -66,21 +66,18 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
 
     /** {@inheritDoc} */
     @Override
-    public GeodeticPoint intersection(final ExtendedEllipsoid ellipsoid,
-                                      final Vector3D position, final Vector3D los)
+    public NormalizedGeodeticPoint intersection(final ExtendedEllipsoid ellipsoid,
+                                                final Vector3D position, final Vector3D los)
         throws RuggedException {
         try {
 
             // compute intersection with ellipsoid
-            final GeodeticPoint gp0 = ellipsoid.pointOnGround(position, los);
-            if (gp0 == null) {
-                throw new RuggedException(RuggedMessages.LINE_OF_SIGHT_DOES_NOT_REACH_GROUND);
-            }
+            final NormalizedGeodeticPoint gp0 = ellipsoid.pointOnGround(position, los, 0.0);
 
             // locate the entry tile along the line-of-sight
             MinMaxTreeTile tile = cache.getTile(gp0.getLatitude(), gp0.getLongitude());
 
-            GeodeticPoint current = null;
+            NormalizedGeodeticPoint current = null;
             double hMax = tile.getMaxElevation();
             while (current == null) {
 
@@ -90,7 +87,7 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
                     // the entry point is behind spacecraft!
                     throw new RuggedException(RuggedMessages.DEM_ENTRY_POINT_IS_BEHIND_SPACECRAFT);
                 }
-                current = ellipsoid.transform(entryP, ellipsoid.getBodyFrame(), null);
+                current = ellipsoid.transform(entryP, ellipsoid.getBodyFrame(), null, tile.getMinimumLongitude());
 
                 if (tile.getLocation(current.getLatitude(), current.getLongitude()) != Tile.Location.IN_TILE) {
                     // the entry point is in another tile
@@ -120,7 +117,7 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
                 final int exitLon  = FastMath.max(0,
                                                   FastMath.min(tile.getLongitudeColumns() - 1,
                                                                tile.getLongitudeIndex(exit.getPoint().getLongitude())));
-                final GeodeticPoint intersection = recurseIntersection(0, ellipsoid, position, los, tile,
+                final NormalizedGeodeticPoint intersection = recurseIntersection(0, ellipsoid, position, los, tile,
                                                                        current, entryLat, entryLon,
                                                                        exit.getPoint(), exitLat, exitLon);
 
@@ -132,7 +129,7 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
 
                     // select next tile after current point
                     final Vector3D forward = new Vector3D(1.0, ellipsoid.transform(exit.getPoint()), STEP, los);
-                    current = ellipsoid.transform(forward, ellipsoid.getBodyFrame(), null);
+                    current = ellipsoid.transform(forward, ellipsoid.getBodyFrame(), null, tile.getMinimumLongitude());
                     tile = cache.getTile(current.getLatitude(), current.getLongitude());
 
                     if (tile.interpolateElevation(current.getLatitude(), current.getLongitude()) >= current.getAltitude()) {
@@ -159,9 +156,9 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
 
     /** {@inheritDoc} */
     @Override
-    public GeodeticPoint refineIntersection(final ExtendedEllipsoid ellipsoid,
-                                            final Vector3D position, final Vector3D los,
-                                            final GeodeticPoint closeGuess)
+    public NormalizedGeodeticPoint refineIntersection(final ExtendedEllipsoid ellipsoid,
+                                                      final Vector3D position, final Vector3D los,
+                                                      final NormalizedGeodeticPoint closeGuess)
         throws RuggedException {
         try {
             if (flatBody) {
@@ -171,7 +168,8 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
                 final Tile tile = cache.getTile(closeGuess.getLatitude(), closeGuess.getLongitude());
                 final Vector3D      exitP  = ellipsoid.pointAtAltitude(position, los, tile.getMinElevation());
                 final Vector3D      entryP = ellipsoid.pointAtAltitude(position, los, tile.getMaxElevation());
-                final GeodeticPoint entry  = ellipsoid.transform(entryP, ellipsoid.getBodyFrame(), null);
+                final NormalizedGeodeticPoint entry  = ellipsoid.transform(entryP, ellipsoid.getBodyFrame(), null,
+                                                                           tile.getMinimumLongitude());
                 return tile.pixelIntersection(entry, ellipsoid.convertLos(entryP, exitP),
                                               tile.getLatitudeIndex(closeGuess.getLatitude()),
                                               tile.getLongitudeIndex(closeGuess.getLongitude()));
@@ -215,11 +213,11 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
      * @exception RuggedException if intersection cannot be found
      * @exception OrekitException if points cannot be converted to geodetic coordinates
      */
-    private GeodeticPoint recurseIntersection(final int depth, final ExtendedEllipsoid ellipsoid,
-                                              final Vector3D position, final Vector3D los,
-                                              final MinMaxTreeTile tile,
-                                              final GeodeticPoint entry, final int entryLat, final int entryLon,
-                                              final GeodeticPoint exit, final int exitLat, final int exitLon)
+    private NormalizedGeodeticPoint recurseIntersection(final int depth, final ExtendedEllipsoid ellipsoid,
+                                                        final Vector3D position, final Vector3D los,
+                                                        final MinMaxTreeTile tile,
+                                                        final NormalizedGeodeticPoint entry, final int entryLat, final int entryLon,
+                                                        final NormalizedGeodeticPoint exit, final int exitLat, final int exitLon)
         throws RuggedException, OrekitException {
 
         if (depth > 30) {
@@ -240,7 +238,7 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
             return null;
         }
 
-        GeodeticPoint previousGP  = entry;
+        NormalizedGeodeticPoint previousGP  = entry;
         int           previousLat = entryLat;
         int           previousLon = entryLon;
 
@@ -257,12 +255,13 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
                 if (longitude >= FastMath.min(entry.getLongitude(), exit.getLongitude()) &&
                     longitude <= FastMath.max(entry.getLongitude(), exit.getLongitude())) {
 
-                    GeodeticPoint crossingGP = null;
+                    NormalizedGeodeticPoint crossingGP = null;
                     if (!flatBody) {
                         try {
                             // full computation of crossing point
                             final Vector3D crossingP = ellipsoid.pointAtLongitude(position, los, longitude);
-                            crossingGP = ellipsoid.transform(crossingP, ellipsoid.getBodyFrame(), null);
+                            crossingGP = ellipsoid.transform(crossingP, ellipsoid.getBodyFrame(), null,
+                                                             tile.getMinimumLongitude());
                         } catch  (RuggedException re) {
                             // in some very rare cases of numerical noise, we miss the crossing point
                             crossingGP = null;
@@ -273,9 +272,10 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
                         final double d  = exit.getLongitude() - entry.getLongitude();
                         final double cN = (exit.getLongitude() - longitude) / d;
                         final double cX = (longitude - entry.getLongitude()) / d;
-                        crossingGP = new GeodeticPoint(cN * entry.getLatitude() + cX * exit.getLatitude(),
-                                                       longitude,
-                                                       cN * entry.getAltitude() + cX * exit.getAltitude());
+                        crossingGP = new NormalizedGeodeticPoint(cN * entry.getLatitude() + cX * exit.getLatitude(),
+                                                                 longitude,
+                                                                 cN * entry.getAltitude() + cX * exit.getAltitude(),
+                                                                 tile.getMinimumLongitude());
                     }
                     final int crossingLat = tile.getLatitudeIndex(crossingGP.getLatitude());
 
@@ -285,9 +285,10 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
 
                     if (inRange(crossingLonBefore, entryLon, exitLon)) {
                         // look for intersection
-                        final GeodeticPoint intersection = recurseIntersection(depth + 1, ellipsoid, position, los, tile,
-                                                                               previousGP, previousLat, previousLon,
-                                                                               crossingGP, crossingLat, crossingLonBefore);
+                        final NormalizedGeodeticPoint intersection =
+                                recurseIntersection(depth + 1, ellipsoid, position, los, tile,
+                                                    previousGP, previousLat, previousLon,
+                                                    crossingGP, crossingLat, crossingLonBefore);
                         if (intersection != null) {
                             return intersection;
                         }
@@ -311,14 +312,15 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
                 if (latitude >= FastMath.min(entry.getLatitude(), exit.getLatitude()) &&
                     latitude <= FastMath.max(entry.getLatitude(), exit.getLatitude())) {
 
-                    GeodeticPoint crossingGP = null;
+                    NormalizedGeodeticPoint crossingGP = null;
                     if (!flatBody) {
                         // full computation of crossing point
                         try {
                             final Vector3D crossingP = ellipsoid.pointAtLatitude(position, los,
                                                                                  tile.getLatitudeAtIndex(crossingLat),
                                                                                  ellipsoid.transform(entry));
-                            crossingGP = ellipsoid.transform(crossingP, ellipsoid.getBodyFrame(), null);
+                            crossingGP = ellipsoid.transform(crossingP, ellipsoid.getBodyFrame(), null,
+                                                             tile.getMinimumLongitude());
                         } catch  (RuggedException re) {
                             // in some very rare cases of numerical noise, we miss the crossing point
                             crossingGP = null;
@@ -329,9 +331,10 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
                         final double d  = exit.getLatitude() - entry.getLatitude();
                         final double cN = (exit.getLatitude() - latitude) / d;
                         final double cX = (latitude - entry.getLatitude()) / d;
-                        crossingGP = new GeodeticPoint(latitude,
-                                                       cN * entry.getLongitude() + cX * exit.getLongitude(),
-                                                       cN * entry.getAltitude()  + cX * exit.getAltitude());
+                        crossingGP = new NormalizedGeodeticPoint(latitude,
+                                                                 cN * entry.getLongitude() + cX * exit.getLongitude(),
+                                                                 cN * entry.getAltitude()  + cX * exit.getAltitude(),
+                                                                 tile.getMinimumLongitude());
                     }
                     final int crossingLon = tile.getLongitudeIndex(crossingGP.getLongitude());
 
@@ -341,7 +344,7 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
 
                     if (inRange(crossingLatBefore, entryLat, exitLat)) {
                         // look for intersection
-                        final GeodeticPoint intersection = recurseIntersection(depth + 1, ellipsoid, position, los, tile,
+                        final NormalizedGeodeticPoint intersection = recurseIntersection(depth + 1, ellipsoid, position, los, tile,
                                                                                previousGP, previousLat, previousLon,
                                                                                crossingGP, crossingLatBefore, crossingLon);
                         if (intersection != null) {
@@ -395,51 +398,48 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
 
         // look for an exit at bottom
         final Vector3D exitP = ellipsoid.pointAtAltitude(position, los, tile.getMinElevation() - STEP);
-        final GeodeticPoint exitGP = ellipsoid.transform(exitP, ellipsoid.getBodyFrame(), null);
+        final NormalizedGeodeticPoint exitGP = ellipsoid.transform(exitP, ellipsoid.getBodyFrame(), null,
+                                                                   tile.getMinimumLongitude());
 
-        // fix longitude discontinuity
-        final double meanTileLongitude = tile.getLongitudeAtIndex(tile.getLongitudeColumns() / 2);
-        final double fixedLongitude    = MathUtils.normalizeAngle(exitGP.getLongitude(), meanTileLongitude);
-
-        switch (tile.getLocation(exitGP.getLatitude(), fixedLongitude)) {
+        switch (tile.getLocation(exitGP.getLatitude(), exitGP.getLongitude())) {
         case SOUTH_WEST :
-            return new LimitPoint(ellipsoid,
+            return new LimitPoint(ellipsoid, tile.getMinimumLongitude(),
                                   selectClosest(ellipsoid.pointAtLatitude(position,  los, tile.getMinimumLatitude(), exitP),
                                                 ellipsoid.pointAtLongitude(position, los, tile.getMinimumLongitude()),
                                                 position),
-                                                true);
+                                  true);
         case WEST :
-            return new LimitPoint(ellipsoid,
+            return new LimitPoint(ellipsoid, tile.getMinimumLongitude(),
                                   ellipsoid.pointAtLongitude(position, los, tile.getMinimumLongitude()),
                                   true);
         case NORTH_WEST:
-            return new LimitPoint(ellipsoid,
+            return new LimitPoint(ellipsoid, tile.getMinimumLongitude(),
                                   selectClosest(ellipsoid.pointAtLatitude(position,  los, tile.getMaximumLatitude(), exitP),
                                                 ellipsoid.pointAtLongitude(position, los, tile.getMinimumLongitude()),
                                                 position),
-                                                true);
+                                  true);
         case NORTH :
-            return new LimitPoint(ellipsoid,
+            return new LimitPoint(ellipsoid, tile.getMinimumLongitude(),
                                   ellipsoid.pointAtLatitude(position, los, tile.getMaximumLatitude(), exitP),
                                   true);
         case NORTH_EAST :
-            return new LimitPoint(ellipsoid,
+            return new LimitPoint(ellipsoid, tile.getMinimumLongitude(),
                                   selectClosest(ellipsoid.pointAtLatitude(position,  los, tile.getMaximumLatitude(), exitP),
                                                 ellipsoid.pointAtLongitude(position, los, tile.getMaximumLongitude()),
                                                 position),
-                                                true);
+                                  true);
         case EAST :
-            return new LimitPoint(ellipsoid,
+            return new LimitPoint(ellipsoid, tile.getMinimumLongitude(),
                                   ellipsoid.pointAtLongitude(position, los, tile.getMaximumLongitude()),
                                   true);
         case SOUTH_EAST :
-            return new LimitPoint(ellipsoid,
+            return new LimitPoint(ellipsoid, tile.getMinimumLongitude(),
                                   selectClosest(ellipsoid.pointAtLatitude(position,  los, tile.getMinimumLatitude(), exitP),
                                                 ellipsoid.pointAtLongitude(position, los, tile.getMaximumLongitude()),
                                                 position),
-                                                true);
+                                  true);
         case SOUTH :
-            return new LimitPoint(ellipsoid,
+            return new LimitPoint(ellipsoid, tile.getMinimumLongitude(),
                                   ellipsoid.pointAtLatitude(position, los, tile.getMinimumLatitude(), exitP),
                                   true);
         case IN_TILE :
@@ -467,21 +467,24 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
     private static class LimitPoint {
 
         /** Coordinates. */
-        private final GeodeticPoint point;
+        private final NormalizedGeodeticPoint point;
 
         /** Limit status. */
         private final boolean side;
 
         /** Simple constructor.
-         * @param cartesian point cartesian
          * @param ellipsoid reference ellipsoid
+         * @param centralLongitude reference longitude lc such that the point longitude will
+         * be normalized between lc-Ï€ and lc+Ï€
+         * @param cartesian Cartesian point
          * @param side if true, the point is on a side limit, otherwise
          * it is on a top/bottom limit
          * @exception OrekitException if geodetic coordinates cannot be computed
          */
-        public LimitPoint(final ExtendedEllipsoid ellipsoid, final Vector3D cartesian, final boolean side)
+        public LimitPoint(final ExtendedEllipsoid ellipsoid, final double centralLongitude,
+                          final Vector3D cartesian, final boolean side)
             throws OrekitException {
-            this(ellipsoid.transform(cartesian, ellipsoid.getBodyFrame(), null), side);
+            this(ellipsoid.transform(cartesian, ellipsoid.getBodyFrame(), null, centralLongitude), side);
         }
 
         /** Simple constructor.
@@ -489,7 +492,7 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
          * @param side if true, the point is on a side limit, otherwise
          * it is on a top/bottom limit
          */
-        public LimitPoint(final GeodeticPoint point, final boolean side) {
+        public LimitPoint(final NormalizedGeodeticPoint point, final boolean side) {
             this.point = point;
             this.side  = side;
         }
@@ -497,7 +500,7 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
         /** Get the point coordinates.
          * @return point coordinates
          */
-        public GeodeticPoint getPoint() {
+        public NormalizedGeodeticPoint getPoint() {
             return point;
         }
 
diff --git a/core/src/main/java/org/orekit/rugged/raster/SimpleTile.java b/core/src/main/java/org/orekit/rugged/raster/SimpleTile.java
index ecb2d701e6188604f57fa6b76d85e9bd4769f627..c2488c50dc58f592b07a665eadef792f74892e6d 100644
--- a/core/src/main/java/org/orekit/rugged/raster/SimpleTile.java
+++ b/core/src/main/java/org/orekit/rugged/raster/SimpleTile.java
@@ -22,6 +22,7 @@ import org.apache.commons.math3.util.Precision;
 import org.orekit.bodies.GeodeticPoint;
 import org.orekit.rugged.api.RuggedException;
 import org.orekit.rugged.api.RuggedMessages;
+import org.orekit.rugged.utils.NormalizedGeodeticPoint;
 
 
 /** Simple implementation of a {@link Tile}.
@@ -245,8 +246,8 @@ public class SimpleTile implements Tile {
 
     /** {@inheritDoc} */
     @Override
-    public GeodeticPoint pixelIntersection(final GeodeticPoint p, final Vector3D los,
-                                           final int latitudeIndex, final int longitudeIndex)
+    public NormalizedGeodeticPoint pixelIntersection(final GeodeticPoint p, final Vector3D los,
+                                                     final int latitudeIndex, final int longitudeIndex)
         throws RuggedException {
 
         // ensure neighboring pixels to not fall out of tile
@@ -312,8 +313,8 @@ public class SimpleTile implements Tile {
 
         }
 
-        final GeodeticPoint p1 = interpolate(t1, p, dxA, dyA, los);
-        final GeodeticPoint p2 = interpolate(t2, p, dxA, dyA, los);
+        final NormalizedGeodeticPoint p1 = interpolate(t1, p, dxA, dyA, los, x00);
+        final NormalizedGeodeticPoint p2 = interpolate(t2, p, dxA, dyA, los, x00);
 
         // select the first point along line-of-sight
         if (p1 == null) {
@@ -332,11 +333,13 @@ public class SimpleTile implements Tile {
      * @param dxP relative coordinate of the start point with respect to current pixel
      * @param dyP relative coordinate of the start point with respect to current pixel
      * @param los direction of the line-of-sight, in geodetic space
+     * @param centralLongitude reference longitude lc such that the point longitude will
+     * be normalized between lc-Ï€ and lc+Ï€
      * @return interpolated point along the line
      */
-    private GeodeticPoint interpolate(final double t, final GeodeticPoint p,
-                                      final double dxP, final double dyP,
-                                      final Vector3D los) {
+    private NormalizedGeodeticPoint interpolate(final double t, final GeodeticPoint p,
+                                                final double dxP, final double dyP,
+                                                final Vector3D los, final double centralLongitude) {
 
         if (Double.isInfinite(t)) {
             return null;
@@ -345,9 +348,10 @@ public class SimpleTile implements Tile {
         final double dx = dxP + t * los.getX() / longitudeStep;
         final double dy = dyP + t * los.getY() / latitudeStep;
         if (dx >= -TOLERANCE && dx <= 1 + TOLERANCE && dy >= -TOLERANCE && dy <= 1 + TOLERANCE) {
-            return new GeodeticPoint(p.getLatitude()  + t * los.getY(),
-                                     p.getLongitude() + t * los.getX(),
-                                     p.getAltitude()  + t * los.getZ());
+            return new NormalizedGeodeticPoint(p.getLatitude()  + t * los.getY(),
+                                               p.getLongitude() + t * los.getX(),
+                                               p.getAltitude()  + t * los.getZ(),
+                                               centralLongitude);
         } else {
             return null;
         }
diff --git a/core/src/main/java/org/orekit/rugged/raster/Tile.java b/core/src/main/java/org/orekit/rugged/raster/Tile.java
index eb91e9d2f14f473062bd25b7774abacc62c6b299..96e91ba9a6d0429d0d1209f52d9b6cd906d63808 100644
--- a/core/src/main/java/org/orekit/rugged/raster/Tile.java
+++ b/core/src/main/java/org/orekit/rugged/raster/Tile.java
@@ -19,6 +19,7 @@ package org.orekit.rugged.raster;
 import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
 import org.orekit.bodies.GeodeticPoint;
 import org.orekit.rugged.api.RuggedException;
+import org.orekit.rugged.utils.NormalizedGeodeticPoint;
 
 /** Interface representing a raster tile.
  * <p>
@@ -193,8 +194,8 @@ public interface Tile extends UpdatableTile {
      * if it lies within the pixel, null otherwise
      * @exception RuggedException if intersection point cannot be computed
      */
-    GeodeticPoint pixelIntersection(GeodeticPoint p, Vector3D los,
-                                    int latitudeIndex, int longitudeIndex)
+    NormalizedGeodeticPoint pixelIntersection(GeodeticPoint p, Vector3D los,
+                                              int latitudeIndex, int longitudeIndex)
         throws RuggedException;
 
     /** Check if a tile covers a ground point.
diff --git a/core/src/main/java/org/orekit/rugged/utils/ExtendedEllipsoid.java b/core/src/main/java/org/orekit/rugged/utils/ExtendedEllipsoid.java
index 2218efb370435158efa78d88dfe336420970a5b4..f02eeeb1517d0eeed2f5dfec84251eef5a0eff63 100644
--- a/core/src/main/java/org/orekit/rugged/utils/ExtendedEllipsoid.java
+++ b/core/src/main/java/org/orekit/rugged/utils/ExtendedEllipsoid.java
@@ -25,6 +25,7 @@ import org.orekit.errors.OrekitException;
 import org.orekit.frames.Frame;
 import org.orekit.rugged.api.RuggedException;
 import org.orekit.rugged.api.RuggedMessages;
+import org.orekit.time.AbsoluteDate;
 
 /** Transform provider from Spacecraft frame to observed body frame.
  * @author Luc Maisonobe
@@ -154,13 +155,26 @@ public class ExtendedEllipsoid extends OneAxisEllipsoid {
     /** Get point on ground along a pixel line of sight.
      * @param position pixel position (in body frame)
      * @param los pixel line-of-sight, not necessarily normalized (in body frame)
+     * @param centralLongitude reference longitude lc such that the point longitude will
+     * be normalized between lc-Ï€ and lc+Ï€
      * @return point on ground
-     * @exception OrekitException if no such point exists (typically line-of-sight missing body)
+     * @exception RuggedException if no such point exists (typically line-of-sight missing body)
      */
-    public GeodeticPoint pointOnGround(final Vector3D position, final Vector3D los)
-        throws OrekitException {
-        return getIntersectionPoint(new Line(position, new Vector3D(1, position, 1e6, los), 1.0e-12),
-                                    position, getBodyFrame(), null);
+    public NormalizedGeodeticPoint pointOnGround(final Vector3D position, final Vector3D los,
+                                                 final double centralLongitude)
+        throws RuggedException {
+        try {
+            final GeodeticPoint gp =
+                    getIntersectionPoint(new Line(position, new Vector3D(1, position, 1e6, los), 1.0e-12),
+                                         position, getBodyFrame(), null);
+            if (gp == null) {
+                throw new RuggedException(RuggedMessages.LINE_OF_SIGHT_DOES_NOT_REACH_GROUND);
+            }
+            return new NormalizedGeodeticPoint(gp.getLatitude(), gp.getLongitude(), gp.getAltitude(),
+                                               centralLongitude);
+        } catch (OrekitException oe) {
+            throw new RuggedException(oe, oe.getSpecifier(), oe.getParts());
+        }
     }
 
     /** Get point at some altitude along a pixel line of sight.
@@ -270,4 +284,21 @@ public class ExtendedEllipsoid extends OneAxisEllipsoid {
         }
     }
 
+    /** Transform a cartesian point to a surface-relative point.
+     * @param point cartesian point
+     * @param frame frame in which cartesian point is expressed
+     * @param date date of the computation (used for frames conversions)
+     * @param centralLongitude reference longitude lc such that the point longitude will
+     * be normalized between lc-Ï€ and lc+Ï€
+     * @return point at the same location but as a surface-relative point
+     * @exception OrekitException if point cannot be converted to body frame
+     */
+    public NormalizedGeodeticPoint transform(final Vector3D point, final Frame frame, final AbsoluteDate date,
+                                             final double centralLongitude)
+        throws OrekitException {
+        final GeodeticPoint gp = transform(point, frame, date);
+        return new NormalizedGeodeticPoint(gp.getLatitude(), gp.getLongitude(), gp.getAltitude(),
+                                           centralLongitude);
+    }
+
 }
diff --git a/core/src/main/java/org/orekit/rugged/utils/NormalizedGeodeticPoint.java b/core/src/main/java/org/orekit/rugged/utils/NormalizedGeodeticPoint.java
new file mode 100644
index 0000000000000000000000000000000000000000..e60879a63b242383b287fe2bad2788b5a908a8a5
--- /dev/null
+++ b/core/src/main/java/org/orekit/rugged/utils/NormalizedGeodeticPoint.java
@@ -0,0 +1,58 @@
+/* Copyright 2013-2014 CS Systèmes d'Information
+ * Licensed to CS Systèmes d'Information (CS) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * CS licenses this file to You 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.
+ */
+package org.orekit.rugged.utils;
+
+import org.apache.commons.math3.util.MathUtils;
+import org.orekit.bodies.GeodeticPoint;
+
+/** Geodetic point whose longitude can be selected with respect to the 2Ï€ boundary.
+ * @author Luc Maisonobe
+ */
+public class NormalizedGeodeticPoint extends GeodeticPoint {
+
+    /** Serializable UID. */
+    private static final long serialVersionUID = 20141016l;
+
+    /** Normalized longitude. */
+    private final double normalizedLongitude;
+
+    /**
+     * Build a new instance. The angular coordinates will be normalized
+     * to ensure     that the latitude is between ±π/2 and the longitude
+     * is between lc-Ï€ and lc+Ï€.
+     *
+     * @param latitude latitude of the point
+     * @param longitude longitude of the point
+     * @param altitude altitude of the point
+     * @param centralLongitude central longitude lc
+     */
+    public NormalizedGeodeticPoint(final double latitude, final double longitude,
+                                   final double altitude, final double centralLongitude) {
+        super(latitude, longitude, altitude);
+        this.normalizedLongitude = MathUtils.normalizeAngle(longitude, centralLongitude);
+    }
+
+    /** Get the longitude.
+     * @return longitude, an angular value in the range [lc-Ï€, lc+Ï€],
+     * where lâ‚€ was selected at construction
+     */
+    @Override
+    public double getLongitude() {
+        return normalizedLongitude;
+    }
+
+}
diff --git a/core/src/test/java/org/orekit/rugged/api/RuggedTest.java b/core/src/test/java/org/orekit/rugged/api/RuggedTest.java
index 88923a1e254bc08a2478651df4c352fe4355eec2..53a30f657716d7090166dde2706be3d3ab8f9c73 100644
--- a/core/src/test/java/org/orekit/rugged/api/RuggedTest.java
+++ b/core/src/test/java/org/orekit/rugged/api/RuggedTest.java
@@ -39,7 +39,6 @@ import org.apache.commons.math3.ode.nonstiff.DormandPrince853Integrator;
 import org.apache.commons.math3.stat.descriptive.SummaryStatistics;
 import org.apache.commons.math3.util.FastMath;
 import org.junit.Assert;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
@@ -277,7 +276,6 @@ public class RuggedTest {
     // the following test is disabled by default
     // it is only used to check timings, and also creates a large (66M) temporary file
     @Test
-    @Ignore
     public void testMayonVolcanoTiming()
         throws RuggedException, OrekitException, URISyntaxException {
 
@@ -925,7 +923,6 @@ public class RuggedTest {
     // the following test is disabled by default
     // it is only used to check timings, and also creates a large (38M) temporary file
     @Test
-    @Ignore
     public void testInverseLocalizationTiming()
         throws RuggedException, OrekitException, URISyntaxException {
 
diff --git a/design/direct-localization-class-diagram.puml b/design/direct-localization-class-diagram.puml
index 8d90bc51fb368f66fe48f1cfc9594643658dacb3..e4e73d4fb2e786a2907851f45fbf7f6f78daa04c 100644
--- a/design/direct-localization-class-diagram.puml
+++ b/design/direct-localization-class-diagram.puml
@@ -30,7 +30,7 @@
     package raster #DDEBD8 {
       interface Tile {
         +interpolateElevation(φ, λ)
-        +pixelIntersection(geodeticPoint, los, φ index, λ index)
+        +pixelIntersection(NormalizedGeodeticPoint, los, φ index, λ index)
       }
     }
 
diff --git a/src/site/markdown/design/technical-choices.md b/src/site/markdown/design/technical-choices.md
index 7c00e542a0b37922b33e607e353038bedc70e39b..3ff7b74014be431a90542e22d08bbde9abbdc3cf 100644
--- a/src/site/markdown/design/technical-choices.md
+++ b/src/site/markdown/design/technical-choices.md
@@ -186,7 +186,7 @@ Arrival on ellipsoid
 --------------------
 
 Once a pixel line-of-sight is known in Earth frame, computing its intersection with a reference ellipsoid is straightforward using an
-instance of OneAxisEllipsoid. The Orekit library computes this intersection as a GeodeticPoint instance on the ellipsoid surface.
+instance of OneAxisEllipsoid. The Orekit library computes this intersection as a NormalizedGeodeticPoint instance on the ellipsoid surface.
 
 The line-of-sight is a straight line in the Cartesian 3D space, and once converted to geodetic coordinates (latitude, longitude,
 altitude), it is not a straight line anymore. Assuming line-of-sight remains a straight line in this space and can be defined by
diff --git a/src/site/xdoc/changes.xml b/src/site/xdoc/changes.xml
index 10a25a72d47b4dc6936f7df392ea5216c36d518f..9cafc4e6961f80eaa30af1ef0a158bf5fc7ccc0d 100644
--- a/src/site/xdoc/changes.xml
+++ b/src/site/xdoc/changes.xml
@@ -22,6 +22,10 @@
   <body>
     <release version="1.0" date="TBD"
              description="TBD">
+      <action dev="luc" type="fix" >
+        Force geodetic points to remain in the same longitude range as the tile of the
+        Digital Elevation Model they belong to.
+      </action>
       <action dev="luc" type="fix" >
         Added a protection agains some extremely rare numerical problems
         in Duvenhage algorithm.
@@ -225,7 +229,7 @@
       </action>
       <action dev="luc" type="update">
         Remove GroundPoint class.
-        We use directly the Orekit GeodeticPoint now.
+        We use directly the Orekit NormalizedGeodeticPoint now.
       </action>
       <action dev="luc" type="add">
         Added ITRF equinox, for applications that rely on it...