Skip to content
Snippets Groups Projects
Commit e01a1d43 authored by Luc Maisonobe's avatar Luc Maisonobe
Browse files

Handle properly tiles boundaries.

Tiles are expected to have no inter-tile gap, i.e. the boundary row/columns are repeated in neighboring tiles.
parent 734dd1ac
No related branches found
No related tags found
No related merge requests found
......@@ -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);
}
}
}
......@@ -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
*/
......
......@@ -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();
}
}
......
......@@ -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);
}
}
}
......
......@@ -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());
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment