From e01a1d4300b99f9534fe94bf16ec61a5bff383c5 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe <luc@orekit.org> Date: Fri, 14 Mar 2014 18:47:01 +0100 Subject: [PATCH] Handle properly tiles boundaries. Tiles are expected to have no inter-tile gap, i.e. the boundary row/columns are repeated in neighboring tiles. --- .../orekit/rugged/core/dem/SimpleTile.java | 42 ++++++++------- .../java/org/orekit/rugged/core/dem/Tile.java | 10 ++++ .../orekit/rugged/core/dem/TilesCache.java | 52 +++++++++++-------- .../dem/CheckedPatternElevationUpdater.java | 11 ++-- .../rugged/core/dem/TilesCacheTest.java | 10 ++-- 5 files changed, 75 insertions(+), 50 deletions(-) diff --git a/rugged-core/src/main/java/org/orekit/rugged/core/dem/SimpleTile.java b/rugged-core/src/main/java/org/orekit/rugged/core/dem/SimpleTile.java index 7fa7f73f..1bf6f104 100644 --- a/rugged-core/src/main/java/org/orekit/rugged/core/dem/SimpleTile.java +++ b/rugged-core/src/main/java/org/orekit/rugged/core/dem/SimpleTile.java @@ -108,12 +108,24 @@ public class SimpleTile implements Tile { return minLatitude; } + /** {@inheritDoc} */ + @Override + public double getMaximumLatitude() { + return minLatitude + latitudeStep * (latitudeRows - 1); + } + /** {@inheritDoc} */ @Override public double getMinimumLongitude() { return minLongitude; } + /** {@inheritDoc} */ + @Override + public double getMaximumLongitude() { + return minLongitude + longitudeStep * (longitudeColumns - 1); + } + /** {@inheritDoc} */ @Override public double getLatitudeStep() { @@ -154,7 +166,12 @@ public class SimpleTile implements Tile { @Override public void setElevation(final int latitudeIndex, final int longitudeIndex, final double elevation) throws RuggedException { - checkIndices(latitudeIndex, longitudeIndex); + if (latitudeIndex < 0 || latitudeIndex > (latitudeRows - 1) || + longitudeIndex < 0 || longitudeIndex > (longitudeColumns - 1)) { + throw new RuggedException(RuggedMessages.OUT_OF_TILE_INDICES, + latitudeIndex, longitudeIndex, + latitudeRows - 1, longitudeColumns - 1); + } minElevation = FastMath.min(minElevation, elevation); maxElevation = FastMath.max(maxElevation, elevation); elevations[latitudeIndex * getLongitudeColumns() + longitudeIndex] = elevation; @@ -174,15 +191,15 @@ public class SimpleTile implements Tile { if (longitudeIndex < 0) { if (latitudeIndex < 0) { return Location.SOUTH_WEST; - } else if (latitudeIndex <= latitudeRows) { + } else if (latitudeIndex <= (latitudeRows - 2)) { return Location.WEST; } else { return Location.NORTH_WEST; } - } else if (longitudeIndex <= longitudeColumns) { + } else if (longitudeIndex <= (longitudeColumns - 2)) { if (latitudeIndex < 0) { return Location.SOUTH; - } else if (latitudeIndex <= latitudeRows) { + } else if (latitudeIndex <= (latitudeRows - 2)) { return Location.IN_TILE; } else { return Location.NORTH; @@ -190,7 +207,7 @@ public class SimpleTile implements Tile { } else { if (latitudeIndex < 0) { return Location.SOUTH_EAST; - } else if (latitudeIndex <= latitudeRows) { + } else if (latitudeIndex <= (latitudeRows - 2)) { return Location.EAST; } else { return Location.NORTH_EAST; @@ -198,19 +215,4 @@ public class SimpleTile implements Tile { } } - /** Check indices. - * @param latitudeIndex - * @param longitudeIndex - * @exception IllegalArgumentException if indices are out of bound - */ - private void checkIndices(int latitudeIndex, int longitudeIndex) - throws RuggedException { - if (latitudeIndex < 0 || latitudeIndex >= latitudeRows || - longitudeIndex < 0 || longitudeIndex >= longitudeColumns) { - throw new RuggedException(RuggedMessages.OUT_OF_TILE_INDICES, - latitudeIndex, longitudeIndex, - latitudeRows - 1, longitudeColumns - 1); - } - } - } diff --git a/rugged-core/src/main/java/org/orekit/rugged/core/dem/Tile.java b/rugged-core/src/main/java/org/orekit/rugged/core/dem/Tile.java index 6956d87f..73972733 100644 --- a/rugged-core/src/main/java/org/orekit/rugged/core/dem/Tile.java +++ b/rugged-core/src/main/java/org/orekit/rugged/core/dem/Tile.java @@ -48,11 +48,21 @@ public interface Tile extends UpdatableTile { */ double getMinimumLatitude(); + /** Get maximum latitude. + * @return maximum latitude + */ + double getMaximumLatitude(); + /** Get minimum longitude. * @return minimum longitude */ double getMinimumLongitude(); + /** Get maximum longitude. + * @return maximum longitude + */ + double getMaximumLongitude(); + /** Get step in latitude (size of one raster element). * @return step in latitude */ diff --git a/rugged-core/src/main/java/org/orekit/rugged/core/dem/TilesCache.java b/rugged-core/src/main/java/org/orekit/rugged/core/dem/TilesCache.java index 7ca1ea95..0d0ed1e7 100644 --- a/rugged-core/src/main/java/org/orekit/rugged/core/dem/TilesCache.java +++ b/rugged-core/src/main/java/org/orekit/rugged/core/dem/TilesCache.java @@ -45,8 +45,8 @@ public class TilesCache<T extends Tile> { /** Search optimized cache. */ private List<TilesStrip> searchCache; - /** Eviction optimized cache. */ - private T[] evictionCache; + /** Eviction queue. */ + private T[] evictionQueue; /** Index for next tile. */ private int next; @@ -61,8 +61,8 @@ public class TilesCache<T extends Tile> { this.updater = updater; this.searchCache = new ArrayList<TilesStrip>(); @SuppressWarnings("unchecked") - final T[] array = (T[]) Array.newInstance(Tile.class, maxTiles); - this.evictionCache = array; + final T[] array = (T[]) Array.newInstance(Tile.class, maxTiles + 1); + this.evictionQueue = array; this.next = 0; } @@ -86,29 +86,36 @@ public class TilesCache<T extends Tile> { private T createTile(final double latitude, final double longitude) throws RuggedException { - if (evictionCache[next] != null) { - // the tile we are creating will evict this older tile - // we need to remove it from the search cache too - for (final Iterator<TilesStrip> iterator = searchCache.iterator(); iterator.hasNext();) { - if (iterator.next().removeTile(evictionCache[next])) { - break; - } - } - } - // create the tile and retrieve its data final T tile = factory.createTile(); updater.updateTile(latitude, longitude, tile); tile.tileUpdateCompleted(); - // store the tile in the eviction cache - evictionCache[next] = tile; - next = (next + 1) % evictionCache.length; - return tile; } + /** Append newly created tile at the end of the eviction queue. + * @param tile tile to append to queue + */ + private void appendToEvictionQueue(final T tile) { + + evictionQueue[next] = tile; + next = (next + 1) % evictionQueue.length; + + if (evictionQueue[next] != null) { + // the cache is full, we need to evict one tile + // from both the eviction cache and the search cache + for (final Iterator<TilesStrip> iterator = searchCache.iterator(); iterator.hasNext();) { + if (iterator.next().removeTile(evictionQueue[next])) { + evictionQueue[next] = null; + return; + } + } + } + + } + /** Get a strip covering a ground point. * @param latitude ground point latitude * @param longitude ground point longitude @@ -137,8 +144,10 @@ public class TilesCache<T extends Tile> { } // no existing strip covers the specified latitude, we need to create a new one - final TilesStrip strip = new TilesStrip(createTile(latitude, longitude)); + final T tile = createTile(latitude, longitude); + final TilesStrip strip = new TilesStrip(tile); searchCache.add(insertionPoint, strip); + appendToEvictionQueue(tile); return strip; } @@ -224,7 +233,7 @@ public class TilesCache<T extends Tile> { */ public TilesStrip(final T tile) { minLatitude = tile.getMinimumLatitude(); - maxLatitude = minLatitude + tile.getLatitudeRows() * tile.getLatitudeStep(); + maxLatitude = tile.getMaximumLatitude(); tiles = new ArrayList<TileDecorator>(); tiles.add(new TileDecorator(tile)); } @@ -273,6 +282,7 @@ public class TilesCache<T extends Tile> { // no existing tile covers the specified ground point, we need to create a new one final T tile = createTile(latitude, longitude); tiles.add(insertionPoint, new TileDecorator(tile)); + appendToEvictionQueue(tile); return tile; } @@ -317,7 +327,7 @@ public class TilesCache<T extends Tile> { /** {@inheritDoc} */ @Override public double getLongitude() { - return tile.getMinimumLongitude() + tile.getLongitudeColumns() * tile.getLongitudeStep(); + return tile.getMaximumLongitude(); } } diff --git a/rugged-core/src/test/java/org/orekit/rugged/core/dem/CheckedPatternElevationUpdater.java b/rugged-core/src/test/java/org/orekit/rugged/core/dem/CheckedPatternElevationUpdater.java index 3eeee4d1..1be46f08 100644 --- a/rugged-core/src/test/java/org/orekit/rugged/core/dem/CheckedPatternElevationUpdater.java +++ b/rugged-core/src/test/java/org/orekit/rugged/core/dem/CheckedPatternElevationUpdater.java @@ -37,12 +37,15 @@ public class CheckedPatternElevationUpdater implements TileUpdater { public void updateTile(double latitude, double longitude, UpdatableTile tile) throws RuggedException { - tile.setGeometry(size * FastMath.floor(latitude / size), - size * FastMath.floor(longitude / size), - size / n, size / n, n, n); + double step = size / (n - 1); + double minLatitude = size * FastMath.floor(latitude / size); + double minLongitude = size * FastMath.floor(longitude / size); + tile.setGeometry(minLatitude, minLongitude, step, step, n, n); for (int i = 0; i < n; ++i) { + int p = (int) FastMath.floor((minLatitude + i * step) / step); for (int j = 0; j < n; ++j) { - tile.setElevation(i, j, (((i ^ j) & 0x1) == 0) ? elevation1 : elevation2); + int q = (int) FastMath.floor((minLongitude + j * step) / step); + tile.setElevation(i, j, (((p ^ q) & 0x1) == 0) ? elevation1 : elevation2); } } } diff --git a/rugged-core/src/test/java/org/orekit/rugged/core/dem/TilesCacheTest.java b/rugged-core/src/test/java/org/orekit/rugged/core/dem/TilesCacheTest.java index 314189cb..ce18aee9 100644 --- a/rugged-core/src/test/java/org/orekit/rugged/core/dem/TilesCacheTest.java +++ b/rugged-core/src/test/java/org/orekit/rugged/core/dem/TilesCacheTest.java @@ -31,7 +31,7 @@ public class TilesCacheTest { public void testSingleTile() throws RuggedException { CountingFactory factory = new CountingFactory(); TilesCache<SimpleTile> cache = new TilesCache<SimpleTile>(factory, - new CheckedPatternElevationUpdater(FastMath.toRadians(3.0), 10, 10.0, 20.0), 1000); + new CheckedPatternElevationUpdater(FastMath.toRadians(3.0), 11, 10.0, 20.0), 1000); SimpleTile tile = cache.getTile(FastMath.toRadians(-23.2), FastMath.toRadians(137.5)); Assert.assertEquals(1, factory.getCount()); Assert.assertEquals(-24.0, FastMath.toDegrees(tile.getMinimumLatitude()), 1.0e-10); @@ -46,7 +46,7 @@ public class TilesCacheTest { public void testEviction() throws RuggedException { CountingFactory factory = new CountingFactory(); TilesCache<SimpleTile> cache = new TilesCache<SimpleTile>(factory, - new CheckedPatternElevationUpdater(FastMath.toRadians(1.0), 10, 10.0, 20.0), 12); + new CheckedPatternElevationUpdater(FastMath.toRadians(1.0), 11, 10.0, 20.0), 12); // fill up the 12 tiles we can keep in cache for (int i = 0; i < 4; ++i) { @@ -92,7 +92,7 @@ public class TilesCacheTest { CountingFactory factory = new CountingFactory(); TilesCache<SimpleTile> cache = new TilesCache<SimpleTile>(factory, - new CheckedPatternElevationUpdater(0.125, 8, 10.0, 20.0), + new CheckedPatternElevationUpdater(0.125, 9, 10.0, 20.0), 12); SimpleTile regularTile = cache.getTile(0.2, 0.6); @@ -120,7 +120,7 @@ public class TilesCacheTest { CountingFactory factory = new CountingFactory(); TilesCache<SimpleTile> cache = new TilesCache<SimpleTile>(factory, - new CheckedPatternElevationUpdater(FastMath.toRadians(1.0), 10, 10.0, 20.0), + new CheckedPatternElevationUpdater(FastMath.toRadians(1.0), 11, 10.0, 20.0), 16); cache.getTile(FastMath.toRadians(1.5), FastMath.toRadians(0.5)); @@ -146,7 +146,7 @@ public class TilesCacheTest { for (int i = 0; i < 10000; ++i) { double lat = 3.0 * generator.nextDouble(); double lon = 4.0 * generator.nextDouble(); - cache.getTile(FastMath.toRadians(lat), FastMath.toRadians(lon)); + cache.getTile(FastMath.toRadians(lat), FastMath.toRadians(lon)); } Assert.assertEquals(16, factory.getCount()); -- GitLab