From ca14ac16d122b4848489d8f355b166731114852c Mon Sep 17 00:00:00 2001
From: Luc Maisonobe <luc@orekit.org>
Date: Mon, 20 Oct 2014 12:04:27 +0200
Subject: [PATCH] Clarified API with respect to DEM tiles overlapping.

---
 .../org/orekit/rugged/api/RuggedMessages.java |   2 +-
 .../intersection/BasicScanAlgorithm.java      |   8 +-
 .../duvenhage/DuvenhageAlgorithm.java         |  24 ++--
 .../org/orekit/rugged/raster/SimpleTile.java  |  10 +-
 .../java/org/orekit/rugged/raster/Tile.java   | 108 ++++++++++++++----
 .../org/orekit/rugged/raster/TileUpdater.java |  59 ++++++++--
 .../org/orekit/rugged/raster/TilesCache.java  |   6 +-
 .../org/orekit/rugged/RuggedMessages_de.utf8  |   4 +-
 .../org/orekit/rugged/RuggedMessages_en.utf8  |   4 +-
 .../org/orekit/rugged/RuggedMessages_es.utf8  |   4 +-
 .../org/orekit/rugged/RuggedMessages_fr.utf8  |   4 +-
 .../org/orekit/rugged/RuggedMessages_gl.utf8  |   4 +-
 .../org/orekit/rugged/RuggedMessages_it.utf8  |   4 +-
 .../duvenhage/DuvenhageAlgorithmTest.java     |   2 +-
 .../orekit/rugged/raster/SimpleTileTest.java  |   6 +-
 15 files changed, 173 insertions(+), 76 deletions(-)

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 374fef7c..47223e49 100644
--- a/core/src/main/java/org/orekit/rugged/api/RuggedMessages.java
+++ b/core/src/main/java/org/orekit/rugged/api/RuggedMessages.java
@@ -53,7 +53,7 @@ public enum RuggedMessages implements Localizable {
     INTERNAL_ERROR("internal error, contact maintenance at {0}"),
     OUT_OF_TILE_INDICES("no data at indices [{0}, {1}], tile only covers from [0, 0] to [{2}, {3}] (inclusive)"),
     OUT_OF_TILE_ANGLES("no data at latitude {0} and longitude {1}, tile covers only latitudes {2} to {3} and longitudes {4} to {5}"),
-    WRONG_TILE("the tile retrieved for latitude {0} and longitude {1} does not cover the point neighborhood (probably wrong overlap handling in TileUpdater)"),
+    TILE_WITHOUT_REQUIRED_NEIGHBORS_SELECTED("the tile selected for latitude {0} and longitude {1} does not contain required point neighborhood"),
     OUT_OF_TIME_RANGE("date {0} is out of time span [{1}, {2}]"),
     UNINITIALIZED_CONTEXT("general context has not been initialized"),
     EMPTY_TILE("tile is empty: {0} ⨉ {1}"),
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 1082570d..401450c9 100644
--- a/core/src/main/java/org/orekit/rugged/intersection/BasicScanAlgorithm.java
+++ b/core/src/main/java/org/orekit/rugged/intersection/BasicScanAlgorithm.java
@@ -169,8 +169,8 @@ public class BasicScanAlgorithm implements IntersectionAlgorithm {
                                                                 ellipsoid.getBodyFrame(), null);
             final Tile          tile      = cache.getTile(projected.getLatitude(), projected.getLongitude());
             return tile.pixelIntersection(projected, ellipsoid.convertLos(projected, los),
-                                          tile.getLatitudeIndex(projected.getLatitude()),
-                                          tile.getLongitudeIndex(projected.getLongitude()));
+                                          tile.getFloorLatitudeIndex(projected.getLatitude()),
+                                          tile.getFloorLongitudeIndex(projected.getLongitude()));
         } catch (OrekitException oe) {
             throw new RuggedException(oe, oe.getSpecifier(), oe.getParts());
         }
@@ -236,7 +236,7 @@ public class BasicScanAlgorithm implements IntersectionAlgorithm {
      * @return index of latitude, truncated at tiles limits
      */
     private int latitudeIndex(final SimpleTile tile, final double latitude) {
-        final int rawIndex = tile.getLatitudeIndex(latitude);
+        final int rawIndex = tile.getFloorLatitudeIndex(latitude);
         return FastMath.min(FastMath.max(0, rawIndex), tile.getLatitudeRows());
     }
 
@@ -246,7 +246,7 @@ public class BasicScanAlgorithm implements IntersectionAlgorithm {
      * @return index of longitude, truncated at tiles limits
      */
     private int longitudeIndex(final SimpleTile tile, final double longitude) {
-        final int rawIndex = tile.getLongitudeIndex(longitude);
+        final int rawIndex = tile.getFloorLongitudeIndex(longitude);
         return FastMath.min(FastMath.max(0, rawIndex), tile.getLongitudeColumns());
     }
 
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 824e55f1..9d3e5d45 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
@@ -89,7 +89,7 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
                 }
                 current = ellipsoid.transform(entryP, ellipsoid.getBodyFrame(), null, tile.getMinimumLongitude());
 
-                if (tile.getLocation(current.getLatitude(), current.getLongitude()) != Tile.Location.IN_TILE) {
+                if (tile.getLocation(current.getLatitude(), current.getLongitude()) != Tile.Location.HAS_INTERPOLATION_NEIGHBORS) {
                     // the entry point is in another tile
                     tile    = cache.getTile(current.getLatitude(), current.getLongitude());
                     hMax    = FastMath.max(hMax, tile.getMaxElevation());
@@ -107,16 +107,16 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
                 // compute intersection with Digital Elevation Model
                 final int entryLat = FastMath.max(0,
                                                   FastMath.min(tile.getLatitudeRows() - 1,
-                                                               tile.getLatitudeIndex(current.getLatitude())));
+                                                               tile.getFloorLatitudeIndex(current.getLatitude())));
                 final int entryLon = FastMath.max(0,
                                                   FastMath.min(tile.getLongitudeColumns() - 1,
-                                                               tile.getLongitudeIndex(current.getLongitude())));
+                                                               tile.getFloorLongitudeIndex(current.getLongitude())));
                 final int exitLat  = FastMath.max(0,
                                                   FastMath.min(tile.getLatitudeRows() - 1,
-                                                               tile.getLatitudeIndex(exit.getPoint().getLatitude())));
+                                                               tile.getFloorLatitudeIndex(exit.getPoint().getLatitude())));
                 final int exitLon  = FastMath.max(0,
                                                   FastMath.min(tile.getLongitudeColumns() - 1,
-                                                               tile.getLongitudeIndex(exit.getPoint().getLongitude())));
+                                                               tile.getFloorLongitudeIndex(exit.getPoint().getLongitude())));
                 final NormalizedGeodeticPoint intersection = recurseIntersection(0, ellipsoid, position, los, tile,
                                                                        current, entryLat, entryLon,
                                                                        exit.getPoint(), exitLat, exitLon);
@@ -171,8 +171,8 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
                 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()));
+                                              tile.getFloorLatitudeIndex(closeGuess.getLatitude()),
+                                              tile.getFloorLongitudeIndex(closeGuess.getLongitude()));
             } else {
                 final Vector3D      delta     = ellipsoid.transform(closeGuess).subtract(position);
                 final double        s         = Vector3D.dotProduct(delta, los) / los.getNormSq();
@@ -180,8 +180,8 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
                                                                     ellipsoid.getBodyFrame(), null);
                 final Tile          tile      = cache.getTile(projected.getLatitude(), projected.getLongitude());
                 return tile.pixelIntersection(projected, ellipsoid.convertLos(projected, los),
-                                              tile.getLatitudeIndex(projected.getLatitude()),
-                                              tile.getLongitudeIndex(projected.getLongitude()));
+                                              tile.getFloorLatitudeIndex(projected.getLatitude()),
+                                              tile.getFloorLongitudeIndex(projected.getLongitude()));
             }
         } catch (OrekitException oe) {
             throw new RuggedException(oe, oe.getSpecifier(), oe.getParts());
@@ -277,7 +277,7 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
                                                                  cN * entry.getAltitude() + cX * exit.getAltitude(),
                                                                  tile.getMinimumLongitude());
                     }
-                    final int crossingLat = tile.getLatitudeIndex(crossingGP.getLatitude());
+                    final int crossingLat = tile.getFloorLatitudeIndex(crossingGP.getLatitude());
 
                     // adjust indices as the crossing point is by definition between the sub-tiles
                     final int crossingLonBefore = crossingLon - (entryLon <= exitLon ? 1 : 0);
@@ -336,7 +336,7 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
                                                                  cN * entry.getAltitude()  + cX * exit.getAltitude(),
                                                                  tile.getMinimumLongitude());
                     }
-                    final int crossingLon = tile.getLongitudeIndex(crossingGP.getLongitude());
+                    final int crossingLon = tile.getFloorLongitudeIndex(crossingGP.getLongitude());
 
                     // adjust indices as the crossing point is by definition between the sub-tiles
                     final int crossingLatBefore = crossingLat - (entryLat <= exitLat ? 1 : 0);
@@ -442,7 +442,7 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
             return new LimitPoint(ellipsoid, tile.getMinimumLongitude(),
                                   ellipsoid.pointAtLatitude(position, los, tile.getMinimumLatitude(), exitP),
                                   true);
-        case IN_TILE :
+        case HAS_INTERPOLATION_NEIGHBORS :
             return new LimitPoint(exitGP, false);
 
         default :
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 c2488c50..2219f3a0 100644
--- a/core/src/main/java/org/orekit/rugged/raster/SimpleTile.java
+++ b/core/src/main/java/org/orekit/rugged/raster/SimpleTile.java
@@ -360,13 +360,13 @@ public class SimpleTile implements Tile {
 
     /** {@inheritDoc} */
     @Override
-    public int getLatitudeIndex(final double latitude) {
+    public int getFloorLatitudeIndex(final double latitude) {
         return (int) FastMath.floor(getDoubleLatitudeIndex(latitude));
     }
 
     /** {@inheritDoc} */
     @Override
-    public int getLongitudeIndex(final double longitude) {
+    public int getFloorLongitudeIndex(final double longitude) {
         return (int) FastMath.floor(getDoubleLontitudeIndex(longitude));
     }
 
@@ -389,8 +389,8 @@ public class SimpleTile implements Tile {
     /** {@inheritDoc} */
     @Override
     public Location getLocation(final double latitude, final double longitude) {
-        final int latitudeIndex  = getLatitudeIndex(latitude);
-        final int longitudeIndex = getLongitudeIndex(longitude);
+        final int latitudeIndex  = getFloorLatitudeIndex(latitude);
+        final int longitudeIndex = getFloorLongitudeIndex(longitude);
         if (longitudeIndex < 0) {
             if (latitudeIndex < 0) {
                 return Location.SOUTH_WEST;
@@ -403,7 +403,7 @@ public class SimpleTile implements Tile {
             if (latitudeIndex < 0) {
                 return Location.SOUTH;
             } else if (latitudeIndex <= (latitudeRows - 2)) {
-                return Location.IN_TILE;
+                return Location.HAS_INTERPOLATION_NEIGHBORS;
             } else {
                 return Location.NORTH;
             }
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 96e91ba9..b42825e5 100644
--- a/core/src/main/java/org/orekit/rugged/raster/Tile.java
+++ b/core/src/main/java/org/orekit/rugged/raster/Tile.java
@@ -32,35 +32,83 @@ import org.orekit.rugged.utils.NormalizedGeodeticPoint;
  */
 public interface Tile extends UpdatableTile {
 
-    /** Enumerate for point location with respect to tile. */
+    /** Enumerate for point location with respect to the interpolation grid of a tile.
+     * <p>
+     * Elevations in a tile are interpolated using the four neighboring points
+     * in a grid: (i, j), (i+1, j), (i, j+1), (i+1), (j+1). This implies that a point
+     * can be interpolated only if the elevation for these four points is available
+     * in the tile. A consequence is that a point in the northernmost row (resp.
+     * easternmost column) miss neighboring points at row j+1 (resp. neighboring points
+     * at column i+1) and therefore cannot be interpolated.
+     * </p>
+     * <p>
+     * This enumerate represent the position of a point taking this off-by-one property
+     * into account, the value {@link #HAS_INTERPOLATION_NEIGHBORS} correspond to points that
+     * do have the necessary four neightbors, whereas the other values correspond to points
+     * that are either completely outside of the tile or within the tile but in either the
+     * northernmost row or easternmost column.
+     * </p>
+     */
     enum Location {
 
-        /** Location for points out of tile, past the South-West corner. */
+        /** Location for points out of tile interpolation grid, in the South-West corner direction. */
         SOUTH_WEST,
 
-        /** Location for points out of tile, past the West edge. */
+        /** Location for points out of tile interpolation grid, in the West edge direction. */
         WEST,
 
-        /** Location for points out of tile, past the North-West corner. */
+        /** Location for points out of tile interpolation grid, in the North-West corner direction.
+         * <p>
+         * The point may still be in the tile, but in the northernmost row thus missing required
+         * interpolation points.
+         * </p>
+         */
         NORTH_WEST,
 
-        /** Location for points out of tile, past the North edge. */
+        /** Location for points out of tile interpolation grid, in the North edge direction.
+         * <p>
+         * The point may still be in the tile, but in the northernmost row thus missing required
+         * interpolation points.
+         * </p>
+         */
         NORTH,
 
-        /** Location for points out of tile, past the North-East corner. */
+        /** Location for points out of tile interpolation grid, in the North-East corner direction.
+         * <p>
+         * The point may still be in the tile, but either in the northernmost row or in the
+         * easternmost column thus missing required interpolation points.
+         * </p>
+         */
         NORTH_EAST,
 
-        /** Location for points out of tile, past the East edge. */
+        /** Location for points out of tile interpolation grid, in the East edge direction.
+         * <p>
+         * The point may still be in the tile, but in the easternmost column thus missing required
+         * interpolation points.
+         * </p>
+         */
         EAST,
 
-        /** Location for points out of tile, past the South-East corner. */
+        /** Location for points out of tile interpolation grid, in the South-East corner direction.
+         * <p>
+         * The point may still be in the tile, but in the easternmost column thus missing required
+         * interpolation points.
+         * </p>
+         */
         SOUTH_EAST,
 
-        /** Location for points out of tile, past the South edge. */
+        /** Location for points out of tile interpolation grid, in the South edge direction. */
         SOUTH,
 
-        /** Location for points within tile. */
-        IN_TILE
+        /** Location for points that do have interpolation neighbors.
+         * <p>
+         * The value corresponds to points that can be interpolated using their four
+         * neighboring points in the grid at indices (i, j), (i+1, j), (i, j+1), (i+1),
+         * (j+1). This implies that these points are neither in the northernmost latitude
+         * row nor in the easternmost longitude column.
+         * </p>
+         */
+        HAS_INTERPOLATION_NEIGHBORS
 
     }
 
@@ -70,8 +118,8 @@ public interface Tile extends UpdatableTile {
      */
     void tileUpdateCompleted() throws RuggedException;
 
-    /** Get minimum latitude.
-     * @return minimum latitude
+    /** Get minimum latitude of grid interpolation points.
+     * @return minimum latitude of grid interpolation points
      * (latitude of the center of the pixels of South row)
      */
     double getMinimumLatitude();
@@ -84,6 +132,14 @@ public interface Tile extends UpdatableTile {
     double getLatitudeAtIndex(int latitudeIndex);
 
     /** Get maximum latitude.
+     * <p>
+     * Beware that as a point at maximum latitude is the northernmost
+     * one of the grid, it doesn't have a northwards neighbor and
+     * therefore calling {@link #getLocation(double, double) getLocation}
+     * on such a latitude will return either {@link Location#NORTH_WEST},
+     * {@link Location#NORTH} or {@link Location#NORTH_EAST}, but can
+     * <em>never</em> return {@link Location#HAS_INTERPOLATION_NEIGHBORS}!
+     * </p>
      * @return maximum latitude
      * (latitude of the center of the pixels of North row)
      */
@@ -103,6 +159,14 @@ public interface Tile extends UpdatableTile {
     double getLongitudeAtIndex(int longitudeIndex);
 
     /** Get maximum longitude.
+     * <p>
+     * Beware that as a point at maximum longitude is the easternmost
+     * one of the grid, it doesn't have an eastwards neighbor and
+     * therefore calling {@link #getLocation(double, double) getLocation}
+     * on such a longitude will return either {@link Location#SOUTH_EAST},
+     * {@link Location#EAST} or {@link Location#NORTH_EAST}, but can
+     * <em>never</em> return {@link Location#HAS_INTERPOLATION_NEIGHBORS}!
+     * </p>
      * @return maximum longitude
      * (longitude of the center of the pixels of East column)
      */
@@ -128,25 +192,23 @@ public interface Tile extends UpdatableTile {
      */
     int getLongitudeColumns();
 
-    /** Get the latitude index of a point.
+    /** Get the floor 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.
+     * The specified latitude is always between index and index+1.
      * </p>
      * @param latitude geodetic latitude
-     * @return latitude index (it may lie outside of the tile!)
+     * @return floor latitude index (it may lie outside of the tile!)
      */
-    int getLatitudeIndex(double latitude);
+    int getFloorLatitudeIndex(double latitude);
 
-    /** Get the longitude index of a point.
+    /** Get the floor longitude index of a point.
      * <p>
-     * This method shift indices 1/2 pixel, so that
-     * the specified longitude is always between index and index+1.
+     * 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!)
+     * @return floor longitude index (it may lie outside of the tile!)
      */
-    int getLongitudeIndex(double longitude);
+    int getFloorLongitudeIndex(double longitude);
 
     /** Get the minimum elevation in the tile.
      * @return minimum elevation in the tile
diff --git a/core/src/main/java/org/orekit/rugged/raster/TileUpdater.java b/core/src/main/java/org/orekit/rugged/raster/TileUpdater.java
index 5b65b87d..106e21f0 100644
--- a/core/src/main/java/org/orekit/rugged/raster/TileUpdater.java
+++ b/core/src/main/java/org/orekit/rugged/raster/TileUpdater.java
@@ -24,23 +24,58 @@ import org.orekit.rugged.api.RuggedException;
  * the image processing mission-specific layer, thus allowing
  * the Rugged library to access the Digital Elevation Model data.
  * </p>
- * @author Luc Maisonobe
+ *  * @author Luc Maisonobe
  */
 public interface TileUpdater {
 
-    /** Set the tile global geometry.
+    /** Update the tile according to the Digital Elevation Model.
      * <p>
-     * As elevations are interpolated within Digital Elevation Model
-     * pixels using four pixels at indices (i, j), (i+1, j), (i, j+1)
-     * (i+1, j+1), the last row and last column of each tile is considered
-     * to be <em>not</em> covered by this tile (as checked using {@link
-     * Tile#getLocation(double, double)}) and should therefore be
-     * in the next tile (Eastwards or Northwards), which should have
-     * on row/column of <em>overlap</em>. This implies that this method
-     * must ensure that the latitude and longitude specified here do
-     * not lie in the last row/column of the returned tile, otherwise
-     * an error will be triggered by caller.
+     * This method is the hook used by the Rugged library to delegate
+     * Digital Elevation Model loading to user-provided mission-specific
+     * code. When this method is called, the specified {@link UpdatableTile
+     * tile} is empty and must be updated by calling {@link
+     * UpdatableTile#setGeometry(double, double, double, double, int, int)
+     * tile.setGeometry} once at the start of the method to set up the tile
+     * geometry, and then calling {@link UpdatableTile#setElevation(int, int,
+     * double) tile.setElevation} once for each pixel in the tile to set the
+     * pixel elevation.
+     * </p>
      * <p>
+     * The implementation must fulfill the requirements:
+     * </p>
+     * <ul>
+     *   <li>
+     *     The tiles must overlap each other by one pixel (i.e. pixels
+     *     that belong to the northernmost row of one tile must also belong
+     *     to the sourthernmost row of another tile and pixels that
+     *     belong to the easternmost column of one tile must also belong
+     *     to the westernmost column of another tile).
+     *   </li>
+     *   <li>
+     *     As elevations are interpolated within Digital Elevation Model
+     *     pixels using four pixels at indices (i, j), (i+1, j), (i, j+1)
+     *     (i+1, j+1). A point in the northernmost row (resp. easternmost
+     *     column) miss neighboring points at row j+1 (resp. neighboring
+     *     points at column i+1) and therefore cannot be interpolated.
+     *     The method should therefore select the northernmost tile if the
+     *     specified latitude is in the overlapping row between two tiles,
+     *     and it should select the easternmost tile if the specified longitude
+     *     is in the overlapping column between two tiles. Failing to do so will
+     *     trigger an error at caller level mentioning the missing required
+     *     neighbors.
+     *   </li>
+     *   <li>
+     *     the elevation at grid point as set when calling {@link
+     *     UpdatableTile#setElevation(int, int, double) tile.setElevation(i, j,
+     *     elevation)} must be the elevation corresponding to the latitude
+     *     {@code minLatitude + i * latitudeStep} and longitude {@code
+     *     minLongitude + j * longitudeStep}, where {@code minLatitude},
+     *     {@code latitudeStep}, {@code minLongitude} and {@code longitudeStep}
+     *     correspond to the parameter of the {@link UpdatableTile#setGeometry(double,
+     *     double, double, double, int, int) tile.setGeometry(minLatitude, minLongitude,
+           latitudeStep, longitudeStep, latitudeRows, longitudeColumns)} call.
+     *   </li>
+     * </ul>
      * @param latitude latitude that must be covered by the tile
      * @param longitude longitude that must be covered by the tile
      * @param tile to update
diff --git a/core/src/main/java/org/orekit/rugged/raster/TilesCache.java b/core/src/main/java/org/orekit/rugged/raster/TilesCache.java
index 64646dd0..4606083a 100644
--- a/core/src/main/java/org/orekit/rugged/raster/TilesCache.java
+++ b/core/src/main/java/org/orekit/rugged/raster/TilesCache.java
@@ -76,9 +76,9 @@ public class TilesCache<T extends Tile> {
     public T getTile(final double latitude, final double longitude)
         throws RuggedException {
         final T tile = getStrip(latitude, longitude).getTile(latitude, longitude);
-        if (tile.getLocation(latitude, longitude) != Tile.Location.IN_TILE) {
+        if (tile.getLocation(latitude, longitude) != Tile.Location.HAS_INTERPOLATION_NEIGHBORS) {
             // this should happen only if user set up an inconsistent TileUpdater
-            throw new RuggedException(RuggedMessages.WRONG_TILE,
+            throw new RuggedException(RuggedMessages.TILE_WITHOUT_REQUIRED_NEIGHBORS_SELECTED,
                                       FastMath.toDegrees(latitude),
                                       FastMath.toDegrees(longitude));
         }
@@ -281,7 +281,7 @@ public class TilesCache<T extends Tile> {
 
                 if (insertionPoint < tiles.size()) {
                     final T tile = tiles.get(insertionPoint).getTile();
-                    if (tile.getLocation(latitude, longitude) == Location.IN_TILE) {
+                    if (tile.getLocation(latitude, longitude) == Location.HAS_INTERPOLATION_NEIGHBORS) {
                         // we have found an existing tile
                         return tile;
                     }
diff --git a/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_de.utf8 b/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_de.utf8
index a93bf8fa..5b6aade0 100644
--- a/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_de.utf8
+++ b/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_de.utf8
@@ -7,8 +7,8 @@ OUT_OF_TILE_INDICES = Keine Angaben im Index, die Ziegel nimmt nur Bezug auf [0,
 # no data at latitude {0} and longitude {1}, tile covers only latitudes {2} to {3} and longitudes {4} to {5}
 OUT_OF_TILE_ANGLES = keine Angaben zu Breite {0} und Länge {1}, die Ziegel nimmt nur Bezug auf die Breite {2} bis {3} und Länge {4} bis {5}
 
-# the tile retrieved for latitude {0} and longitude {1} does not cover the point neighborhood (probably wrong overlap handling in TileUpdater)
-WRONG_TILE = <MISSING TRANSLATION>
+# the tile selected for latitude {0} and longitude {1} does not contain required point neighborhood
+TILE_WITHOUT_REQUIRED_NEIGHBORS_SELECTED = <MISSING TRANSLATION>
 
 # date {0} is out of time span [{1}, {2}]
 OUT_OF_TIME_RANGE = Angabe {0} ist außerhalb der Zeitspanne [{1}, {2}]
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 8bb8983e..9cfe08af 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
@@ -7,8 +7,8 @@ OUT_OF_TILE_INDICES = no data at indices [{0}, {1}], tile only covers from [0, 0
 # no data at latitude {0} and longitude {1}, tile covers only latitudes {2} to {3} and longitudes {4} to {5}
 OUT_OF_TILE_ANGLES = no data at latitude {0} and longitude {1}, tile covers only latitudes {2} to {3} and longitudes {4} to {5}
 
-# the tile retrieved for latitude {0} and longitude {1} does not cover the point neighborhood (probably wrong overlap handling in TileUpdater)
-WRONG_TILE = the tile retrieved for latitude {0} and longitude {1} does not cover the point neighborhood (probably wrong overlap handling in TileUpdater)
+# the tile selected for latitude {0} and longitude {1} does not contain required point neighborhood
+TILE_WITHOUT_REQUIRED_NEIGHBORS_SELECTED = the tile selected for latitude {0} and longitude {1} does not contain required point neighborhood
 
 # date {0} is out of time span [{1}, {2}]
 OUT_OF_TIME_RANGE = date {0} is out of time span [{1}, {2}]
diff --git a/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_es.utf8 b/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_es.utf8
index 88aad615..93f48949 100644
--- a/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_es.utf8
+++ b/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_es.utf8
@@ -7,8 +7,8 @@ OUT_OF_TILE_INDICES = no hay datos en los índices [{0}, {1}], la faceta sólo c
 # no data at latitude {0} and longitude {1}, tile covers only latitudes {2} to {3} and longitudes {4} to {5}
 OUT_OF_TILE_ANGLES = no hay datos para la latitud {0} y la longitud {1}, la faceta sólo cubre las latitudes de {2} a {3} y las longitudes de {4} a {5}
 
-# the tile retrieved for latitude {0} and longitude {1} does not cover the point neighborhood (probably wrong overlap handling in TileUpdater)
-WRONG_TILE = <MISSING TRANSLATION>
+# the tile selected for latitude {0} and longitude {1} does not contain required point neighborhood
+TILE_WITHOUT_REQUIRED_NEIGHBORS_SELECTED = <MISSING TRANSLATION>
 
 # date {0} is out of time span [{1}, {2}]
 OUT_OF_TIME_RANGE = la fecha {0} está fuera del intervalo temporal [{1}, {2}]
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 56312d3d..5e13858c 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
@@ -7,8 +7,8 @@ OUT_OF_TILE_INDICES = aucune donnée aux indices [{0}, {1}], la tuile ne couvre
 # no data at latitude {0} and longitude {1}, tile covers only latitudes {2} to {3} and longitudes {4} to {5}
 OUT_OF_TILE_ANGLES = aucune donnée à la latitude {0} et à la longitude {1}, la tuile ne couvre que les latitudes de {2} à {3} et les longitudes de {4} à {5}
 
-# the tile retrieved for latitude {0} and longitude {1} does not cover the point neighborhood (probably wrong overlap handling in TileUpdater)
-WRONG_TILE = la tuile fournie pourla latitude {0} et à la longitude {1} ne couvre pas le voisinage de ce point (il s''agit probablement d''un problème de gestion des recouvrements dans le TileUpdater)
+# the tile selected for latitude {0} and longitude {1} does not contain required point neighborhood
+TILE_WITHOUT_REQUIRED_NEIGHBORS_SELECTED = la tuile sélectionnée pour la latitude {0} et la longitude {1} ne contient pas le voisinage requis pour ce point
 
 # date {0} is out of time span [{1}, {2}]
 OUT_OF_TIME_RANGE = la date {0} est hors de la plage temporelle [{1}, {2}]
diff --git a/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_gl.utf8 b/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_gl.utf8
index a3dbc6dd..2568ab8d 100644
--- a/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_gl.utf8
+++ b/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_gl.utf8
@@ -7,8 +7,8 @@ OUT_OF_TILE_INDICES = non hai datos nos índices [{0}, {1}], a faceta só cubre
 # no data at latitude {0} and longitude {1}, tile covers only latitudes {2} to {3} and longitudes {4} to {5}
 OUT_OF_TILE_ANGLES = non hai datos para a latitude {0} e a lonxitude {1}, a faceta só cubre as latitudes de {2} a {3} e as lonxitudes de {4} a {5}
 
-# the tile retrieved for latitude {0} and longitude {1} does not cover the point neighborhood (probably wrong overlap handling in TileUpdater)
-WRONG_TILE = <MISSING TRANSLATION>
+# the tile selected for latitude {0} and longitude {1} does not contain required point neighborhood
+TILE_WITHOUT_REQUIRED_NEIGHBORS_SELECTED = <MISSING TRANSLATION>
 
 # date {0} is out of time span [{1}, {2}]
 OUT_OF_TIME_RANGE = a data {0} está fora do intervalo temporal [{1}, {2}]
diff --git a/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_it.utf8 b/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_it.utf8
index f7e348a4..aad138fa 100644
--- a/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_it.utf8
+++ b/core/src/main/resources/assets/org/orekit/rugged/RuggedMessages_it.utf8
@@ -7,8 +7,8 @@ OUT_OF_TILE_INDICES = nessun dato agli indici [{0}, {1}], il quadrante non copre
 # no data at latitude {0} and longitude {1}, tile covers only latitudes {2} to {3} and longitudes {4} to {5}
 OUT_OF_TILE_ANGLES = nessun dato alla latitudine {0} e alla longitudine {1}, il quadrante non copre che le latitudini da {2} a {3} et les longitudes de {4} à {5}
 
-# the tile retrieved for latitude {0} and longitude {1} does not cover the point neighborhood (probably wrong overlap handling in TileUpdater)
-WRONG_TILE = <MISSING TRANSLATION>
+# the tile selected for latitude {0} and longitude {1} does not contain required point neighborhood
+TILE_WITHOUT_REQUIRED_NEIGHBORS_SELECTED = <MISSING TRANSLATION>
 
 # date {0} is out of time span [{1}, {2}]
 OUT_OF_TIME_RANGE = la data {0} è fuori dell''intervallo temporale [{1}, {2}]
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 37fbfc10..ec3a2e1b 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
@@ -99,7 +99,7 @@ public class DuvenhageAlgorithmTest extends AbstractAlgorithmTest {
                                    new Vector3D(-3010311.9672771087, 5307094.8081077365, 1852867.7919871407),
                                    new Vector3D(0.3953329359154183, -0.8654901360032332, -0.30763402650162286));
         } catch (RuggedException re) {
-            Assert.assertEquals(RuggedMessages.WRONG_TILE, re.getSpecifier());
+            Assert.assertEquals(RuggedMessages.TILE_WITHOUT_REQUIRED_NEIGHBORS_SELECTED, 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 ac0d4f97..f2704894 100644
--- a/core/src/test/java/org/orekit/rugged/raster/SimpleTileTest.java
+++ b/core/src/test/java/org/orekit/rugged/raster/SimpleTileTest.java
@@ -89,7 +89,7 @@ public class SimpleTileTest {
         Assert.assertEquals(Location.WEST,       tile.getLocation( 6.0,  1.0));
         Assert.assertEquals(Location.NORTH_WEST, tile.getLocation(12.0,  1.0));
         Assert.assertEquals(Location.SOUTH,      tile.getLocation( 0.0, 22.0));
-        Assert.assertEquals(Location.IN_TILE,    tile.getLocation( 6.0, 22.0));
+        Assert.assertEquals(Location.HAS_INTERPOLATION_NEIGHBORS,    tile.getLocation( 6.0, 22.0));
         Assert.assertEquals(Location.NORTH,      tile.getLocation(12.0, 22.0));
         Assert.assertEquals(Location.SOUTH_EAST, tile.getLocation( 0.0, 43.0));
         Assert.assertEquals(Location.EAST,       tile.getLocation( 6.0, 43.0));
@@ -134,7 +134,7 @@ public class SimpleTileTest {
         // 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);
+        int retrievedLatIndex = tile.getFloorLatitudeIndex(latWestColumn51);
         Assert.assertEquals(50, retrievedLatIndex);
         Assert.assertTrue(tile.getLatitudeAtIndex(retrievedLatIndex) < latWestColumn51);
         Assert.assertTrue(latWestColumn51 < tile.getLatitudeAtIndex(retrievedLatIndex + 1));
@@ -144,7 +144,7 @@ public class SimpleTileTest {
         // 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);
+        int retrievedLonIndex = tile.getFloorLongitudeIndex(lonSouthRow24);
         Assert.assertEquals(23, retrievedLonIndex);
         Assert.assertTrue(tile.getLongitudeAtIndex(retrievedLonIndex) < lonSouthRow24);
         Assert.assertTrue(lonSouthRow24 < tile.getLongitudeAtIndex(retrievedLonIndex + 1));
-- 
GitLab