diff --git a/core/src/main/java/org/orekit/rugged/api/RuggedMessages.java b/core/src/main/java/org/orekit/rugged/api/RuggedMessages.java
index 044571dd9b86d4fbf0a194c7bcaeffdc6abd3c6e..0f63da906b0335009f4fad7e5af68b8f0f4ef440 100644
--- a/core/src/main/java/org/orekit/rugged/api/RuggedMessages.java
+++ b/core/src/main/java/org/orekit/rugged/api/RuggedMessages.java
@@ -57,6 +57,7 @@ public enum RuggedMessages implements Localizable {
     UNINITIALIZED_CONTEXT("general context has not been initialized"),
     EMPTY_TILE("tile is empty: {0} ⨉ {1}"),
     UNKNOWN_SENSOR("unknown sensor {0}"),
+    LINE_OF_SIGHT_DOES_NOT_REACH_GROUND("line-of-sight does not reach ground"),
     LINE_OF_SIGHT_NEVER_CROSSES_LATITUDE("line-of-sight never crosses latitude {0}"),
     LINE_OF_SIGHT_NEVER_CROSSES_LONGITUDE("line-of-sight never crosses longitude {0}"),
     LINE_OF_SIGHT_NEVER_CROSSES_ALTITUDE("line-of-sight never crosses altitude {0}"),
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 9079bc36c0d74dd1dd5a04323b93223f77b3a1a9..ac359e18104440393675b71133d775f8e9103b77 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,6 +18,7 @@ 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;
@@ -72,6 +73,9 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
 
             // 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);
+            }
 
             // locate the entry tile along the line-of-sight
             MinMaxTreeTile tile = cache.getTile(gp0.getLatitude(), gp0.getLongitude());
@@ -381,7 +385,11 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
         final Vector3D exitP = ellipsoid.pointAtAltitude(position, los, tile.getMinElevation() - STEP);
         final GeodeticPoint exitGP = ellipsoid.transform(exitP, ellipsoid.getBodyFrame(), null);
 
-        switch (tile.getLocation(exitGP.getLatitude(), exitGP.getLongitude())) {
+        // 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)) {
         case SOUTH_WEST :
             return new LimitPoint(ellipsoid,
                                   selectClosest(ellipsoid.pointAtLatitude(position,  los, tile.getMinimumLatitude(), exitP),
diff --git a/core/src/main/java/org/orekit/rugged/intersection/duvenhage/MinMaxTreeTile.java b/core/src/main/java/org/orekit/rugged/intersection/duvenhage/MinMaxTreeTile.java
index 5c2ea740d9e553ad9abf551e43dbc467a21fdb1c..273bb4d06c5e07d0a91522bdc3e4675b55dbee65 100644
--- a/core/src/main/java/org/orekit/rugged/intersection/duvenhage/MinMaxTreeTile.java
+++ b/core/src/main/java/org/orekit/rugged/intersection/duvenhage/MinMaxTreeTile.java
@@ -30,7 +30,7 @@ import org.orekit.rugged.raster.SimpleTile;
  * Level n-1, which is the deepest one, is computed from the raw pixels by
  * merging adjacent pixels pairs columns (i.e. pixels at indices (i, 2j)
  * and (i, 2j+1) are merged together by computing and storing the minimum
- * and maxium in a sub-tile. Level n-1 therefore has the same number of rows
+ * and maximum in a sub-tile. Level n-1 therefore has the same number of rows
  * but half the number of columns of the raw tile, and its sub-tiles are
  * 1 pixel high and 2 pixels wide. Level n-2 is computed from level n-1 by
  * merging sub-tiles rows. Level n-2 therefore has half the number of rows
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 21d5547e5a65e820263aab611a5f3f2b036012bd..eb91e9d2f14f473062bd25b7774abacc62c6b299 100644
--- a/core/src/main/java/org/orekit/rugged/raster/Tile.java
+++ b/core/src/main/java/org/orekit/rugged/raster/Tile.java
@@ -21,6 +21,12 @@ import org.orekit.bodies.GeodeticPoint;
 import org.orekit.rugged.api.RuggedException;
 
 /** Interface representing a raster tile.
+ * <p>
+ * The elevations are considered to be at the <em>center</em> of each pixels.
+ * The minimum latitude and longitude hence correspond to the <em>center</em>
+ * of the most South-West pixel, and the maximum latitude and longitude
+ * correspond to the <em>center</em> of the most North-East pixel.
+ * </p>
  * @author Luc Maisonobe
  */
 public interface Tile extends UpdatableTile {
@@ -65,33 +71,39 @@ public interface Tile extends UpdatableTile {
 
     /** Get minimum latitude.
      * @return minimum latitude
+     * (latitude of the center of the pixels of South row)
      */
     double getMinimumLatitude();
 
     /** Get the latitude at some index.
      * @param latitudeIndex latitude index
      * @return latitude at the specified index
+     * (latitude of the center of the pixels of specified row)
      */
     double getLatitudeAtIndex(int latitudeIndex);
 
     /** Get maximum latitude.
      * @return maximum latitude
+     * (latitude of the center of the pixels of North row)
      */
     double getMaximumLatitude();
 
     /** Get minimum longitude.
      * @return minimum longitude
+     * (longitude of the center of the pixels of West column)
      */
     double getMinimumLongitude();
 
     /** Get the longitude at some index.
      * @param longitudeIndex longitude index
      * @return longitude at the specified index
+     * (longitude of the center of the pixels of specified column)
      */
     double getLongitudeAtIndex(int longitudeIndex);
 
     /** Get maximum longitude.
      * @return maximum longitude
+     * (longitude of the center of the pixels of East column)
      */
     double getMaximumLongitude();
 
@@ -116,13 +128,21 @@ public interface Tile extends UpdatableTile {
     int getLongitudeColumns();
 
     /** Get the latitude index of a point.
+     * <p>
+     * This method shift indices 1/2 pixel, so that
+     * the specified latitude is always between index and index+1.
+     * </p>
      * @param latitude geodetic latitude
-     * @return latirute index (it may lie outside of the tile!)
+     * @return latitude index (it may lie outside of the tile!)
      */
     int getLatitudeIndex(double latitude);
 
     /** Get the longitude index of a point.
-     * @param longitude geodetic latitude
+     * <p>
+     * This method shift indices 1/2 pixel, so that
+     * the specified longitude is always between index and index+1.
+     * </p>
+     * @param longitude geodetic longitude
      * @return longitude index (it may lie outside of the tile!)
      */
     int getLongitudeIndex(double longitude);
diff --git a/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_en.utf8 b/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_en.utf8
index 587c7eb1baa279cffde6a495a6917daa637cc78d..118da04a8d37f0a9c650aa6711e6f899732802c0 100644
--- a/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_en.utf8
+++ b/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_en.utf8
@@ -19,6 +19,9 @@ EMPTY_TILE = tile is empty: {0} ⨉ {1}
 # unknown sensor {0}
 UNKNOWN_SENSOR = unknown sensor {0}
 
+# line-of-sight does not reach ground
+LINE_OF_SIGHT_DOES_NOT_REACH_GROUND = line-of-sight does not reach ground
+
 # line-of-sight never crosses latitude {0}
 LINE_OF_SIGHT_NEVER_CROSSES_LATITUDE = line-of-sight never crosses latitude {0}
 
diff --git a/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_fr.utf8 b/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_fr.utf8
index 825795b4dcba86e9ce285976c93e05e64e79c5e6..dbbd3973ec50be29cb9e2470279e4a56b34b7831 100644
--- a/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_fr.utf8
+++ b/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_fr.utf8
@@ -19,6 +19,9 @@ EMPTY_TILE = la tuile est vide : {0} ⨉ {1}
 # unknown sensor {0}
 UNKNOWN_SENSOR = capteur {0} inconnu
 
+# line-of-sight does not reach ground
+LINE_OF_SIGHT_DOES_NOT_REACH_GROUND = la ligne de visée n''atteint pas le sol
+
 # line-of-sight never crosses latitude {0}
 LINE_OF_SIGHT_NEVER_CROSSES_LATITUDE = la ligne de visée ne franchit jamais la latitude {0}
 
diff --git a/core/src/test/java/org/orekit/rugged/api/RuggedMessagesTest.java b/core/src/test/java/org/orekit/rugged/api/RuggedMessagesTest.java
index abde2c084c32ffdd4b53e80a323426902e43971d..9b7d06081d59da6d8361c24a531878951235b7cf 100644
--- a/core/src/test/java/org/orekit/rugged/api/RuggedMessagesTest.java
+++ b/core/src/test/java/org/orekit/rugged/api/RuggedMessagesTest.java
@@ -29,7 +29,7 @@ public class RuggedMessagesTest {
 
     @Test
     public void testMessageNumber() {
-        Assert.assertEquals(13, RuggedMessages.values().length);
+        Assert.assertEquals(14, RuggedMessages.values().length);
     }
 
     @Test
diff --git a/core/src/test/java/org/orekit/rugged/intersection/duvenhage/DuvenhageAlgorithmTest.java b/core/src/test/java/org/orekit/rugged/intersection/duvenhage/DuvenhageAlgorithmTest.java
index 8c5bc03b4d75610d1896fb26ea52a20fed472b35..ce1e1f9c74c53b606fb4ade18013dd92cd074860 100644
--- a/core/src/test/java/org/orekit/rugged/intersection/duvenhage/DuvenhageAlgorithmTest.java
+++ b/core/src/test/java/org/orekit/rugged/intersection/duvenhage/DuvenhageAlgorithmTest.java
@@ -18,10 +18,12 @@ package org.orekit.rugged.intersection.duvenhage;
 
 
 import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
+import org.junit.Assert;
 import org.junit.Test;
 import org.orekit.bodies.GeodeticPoint;
 import org.orekit.errors.OrekitException;
 import org.orekit.rugged.api.RuggedException;
+import org.orekit.rugged.api.RuggedMessages;
 import org.orekit.rugged.intersection.AbstractAlgorithmTest;
 import org.orekit.rugged.intersection.IntersectionAlgorithm;
 import org.orekit.rugged.intersection.duvenhage.DuvenhageAlgorithm;
@@ -55,4 +57,18 @@ public class DuvenhageAlgorithmTest extends AbstractAlgorithmTest {
         checkIntersection(position, los, intersection);
     }
 
+    @Test
+    public void testWrongPositionMissesGround() throws RuggedException, OrekitException {
+        setUpMayonVolcanoContext();
+        final IntersectionAlgorithm algorithm = createAlgorithm(updater, 8);
+        Vector3D position = new Vector3D(7.551889113912788E9, -3.173692685491814E10, 1.5727517321541348E9);
+        Vector3D los = new Vector3D(0.010401349221417867, -0.17836068905951286, 0.9839101973923178);
+        try {
+            algorithm.intersection(earth, position, los);
+            Assert.fail("an exception should have been thrown");
+        } catch (RuggedException re) {
+            Assert.assertEquals(RuggedMessages.LINE_OF_SIGHT_DOES_NOT_REACH_GROUND, re.getSpecifier());
+        }
+    }
+
 }
diff --git a/core/src/test/java/org/orekit/rugged/raster/SimpleTileTest.java b/core/src/test/java/org/orekit/rugged/raster/SimpleTileTest.java
index a71c1ce171a7b9fb20f183ae4ce879d1020fb108..ac0d4f974b11f3dd96a46359366c75bd6bc82fb6 100644
--- a/core/src/test/java/org/orekit/rugged/raster/SimpleTileTest.java
+++ b/core/src/test/java/org/orekit/rugged/raster/SimpleTileTest.java
@@ -115,6 +115,42 @@ public class SimpleTileTest {
         checkOutOfBound( 50, 200, tile);
     }
 
+    @Test
+    public void testIndexShift() throws RuggedException {
+
+        SimpleTile tile = new SimpleTileFactory().createTile();
+        tile.setGeometry(1.0, 2.0, 0.1, 0.2, 100, 200);
+        tile.setElevation(50, 100, 1000.0);
+        tile.tileUpdateCompleted();
+
+        // indices correspond to pixels centers
+        double latCenterColumn50 = tile.getLatitudeAtIndex(50);
+        double latCenterColumn51 = tile.getLatitudeAtIndex(51);
+        double lonCenterRow23    = tile.getLongitudeAtIndex(23);
+        double lonCenterRow24    = tile.getLongitudeAtIndex(24);
+
+        // getLatitudeIndex shift indices 1/2 pixel, so that
+        // the specified latitude is always between index and index+1
+        // so despite latWestColumn51 is very close to column 51 center,
+        // getLatitudeIndex should return 50
+        double latWestColumn51   = 0.001 * latCenterColumn50 + 0.999 * latCenterColumn51;
+        int retrievedLatIndex = tile.getLatitudeIndex(latWestColumn51);
+        Assert.assertEquals(50, retrievedLatIndex);
+        Assert.assertTrue(tile.getLatitudeAtIndex(retrievedLatIndex) < latWestColumn51);
+        Assert.assertTrue(latWestColumn51 < tile.getLatitudeAtIndex(retrievedLatIndex + 1));
+
+        // getLongitudeIndex shift indices 1/2 pixel, so that
+        // the specified longitude is always between index and index+1
+        // so despite lonSouthRow24 is very close to row 24 center,
+        // getLongitudeIndex should return 23
+        double lonSouthRow24     = 0.001 * lonCenterRow23    + 0.999 * lonCenterRow24;
+        int retrievedLonIndex = tile.getLongitudeIndex(lonSouthRow24);
+        Assert.assertEquals(23, retrievedLonIndex);
+        Assert.assertTrue(tile.getLongitudeAtIndex(retrievedLonIndex) < lonSouthRow24);
+        Assert.assertTrue(lonSouthRow24 < tile.getLongitudeAtIndex(retrievedLonIndex + 1));
+
+    }
+
     private void checkOutOfBound(int i, int j, Tile tile) {
         try {
             tile.setElevation(i, j, 1000.0);
diff --git a/core/src/test/java/org/orekit/rugged/raster/TilesCacheTest.java b/core/src/test/java/org/orekit/rugged/raster/TilesCacheTest.java
index 620b03fdbd31ab672e6e94fbbd8c18f90b7ed183..cad96cd479813d85881c9f9ea4ddf83b50be490e 100644
--- a/core/src/test/java/org/orekit/rugged/raster/TilesCacheTest.java
+++ b/core/src/test/java/org/orekit/rugged/raster/TilesCacheTest.java
@@ -77,7 +77,7 @@ public class TilesCacheTest {
         cache.getTile(FastMath.toRadians(20.5), FastMath.toRadians(30.5));
         Assert.assertEquals(14, factory.getCount());
 
-        // evict all the tiles, goind to a completely different zone
+        // evict all the tiles, going to a completely different zone
         for (int i = 0; i < 4; ++i) {
             for (int j = 0; j < 3; ++j) {
                 cache.getTile(FastMath.toRadians(40.5 + i), FastMath.toRadians(90.5 + j));
diff --git a/src/site/xdoc/changes.xml b/src/site/xdoc/changes.xml
index 2751dc151d5072dfec39c171d295649752397994..1c42211de3f9d700b20ad53bdd6c6b0cd476bb94 100644
--- a/src/site/xdoc/changes.xml
+++ b/src/site/xdoc/changes.xml
@@ -22,6 +22,9 @@
   <body>
     <release version="1.0" date="TBD"
              description="TBD">
+      <action dev="luc" type="fix">
+        Added detection of wrong position/line-of-sight that misses the ground.
+      </action>
       <action dev="luc" type="add">
         Added a way to reuse transform interpolator from one run to another
         by dumping its state into a file, thus avoiding costly initialization.