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

Added a getMergeLevel method to identify when pixels share min/max.

This is a first step towards duvenhage's algorithm.
parent 8808fd9b
No related branches found
No related tags found
No related merge requests found
...@@ -69,6 +69,7 @@ public class MinMaxTreeTile extends SimpleTile { ...@@ -69,6 +69,7 @@ public class MinMaxTreeTile extends SimpleTile {
* @return number of kd-tree levels * @return number of kd-tree levels
* @see #getMinElevation(int, int, int) * @see #getMinElevation(int, int, int)
* @see #getMaxElevation(int, int, int) * @see #getMaxElevation(int, int, int)
* @see #getMergeLevel(int, int, int, int)
*/ */
public int getLevels() { public int getLevels() {
return start.length; return start.length;
...@@ -81,6 +82,7 @@ public class MinMaxTreeTile extends SimpleTile { ...@@ -81,6 +82,7 @@ public class MinMaxTreeTile extends SimpleTile {
* @return minimum elevation * @return minimum elevation
* @see #getLevels() * @see #getLevels()
* @see #getMaxElevation(int, int, int) * @see #getMaxElevation(int, int, int)
* @see #getMergeLevel(int, int, int, int)
*/ */
public double getMinElevation(final int i, final int j, final int level) { public double getMinElevation(final int i, final int j, final int level) {
...@@ -103,6 +105,7 @@ public class MinMaxTreeTile extends SimpleTile { ...@@ -103,6 +105,7 @@ public class MinMaxTreeTile extends SimpleTile {
* @return maximum elevation * @return maximum elevation
* @see #getLevels() * @see #getLevels()
* @see #getMinElevation(int, int, int) * @see #getMinElevation(int, int, int)
* @see #getMergeLevel(int, int, int, int)
*/ */
public double getMaxElevation(final int i, final int j, final int level) { public double getMaxElevation(final int i, final int j, final int level) {
...@@ -118,6 +121,40 @@ public class MinMaxTreeTile extends SimpleTile { ...@@ -118,6 +121,40 @@ public class MinMaxTreeTile extends SimpleTile {
} }
/** Get the largest level at which two pixels are merged in the same min/max sub-tile.
* @param i1 row index of first pixel
* @param j1 column index of first pixel
* @param i2 row index of second pixel
* @param j2 column index of sedonc pixel
* @return largest level at which two pixels are merged in the same min/max sub-tile,
* or negative if they are never merged in the same sub-tile
* @see #getLevels()
* @see #getMinElevation(int, int, int)
* @see #getMaxElevation(int, int, int)
*/
public int getMergeLevel(final int i1, final int j1, final int i2, final int j2) {
int largest = -1;
for (int level = 0; level < start.length; ++level) {
// compute indices in level merged array
final int k = start.length - level;
final int rowShift = k / 2;
final int colShift = (k + 1) / 2;
final int levelI1 = i1 >> rowShift;
final int levelJ1 = j1 >> colShift;
final int levelI2 = i2 >> rowShift;
final int levelJ2 = j2 >> colShift;
if (levelI1 != levelI2 || levelJ1 != levelJ2) {
return largest;
}
largest = level;
}
return largest;
}
/** Recursive setting of tree levels. /** Recursive setting of tree levels.
* <p> * <p>
* The following algorithms works for any array shape, even with * The following algorithms works for any array shape, even with
......
...@@ -31,9 +31,7 @@ public class MinMaxTreeTileTest { ...@@ -31,9 +31,7 @@ public class MinMaxTreeTileTest {
public void testSizeTall() public void testSizeTall()
throws RuggedException, SecurityException, NoSuchFieldException, throws RuggedException, SecurityException, NoSuchFieldException,
IllegalArgumentException, IllegalAccessException { IllegalArgumentException, IllegalAccessException {
MinMaxTreeTile tile = new MinMaxTreeTileFactory().createTile(); MinMaxTreeTile tile = createTile(107, 19);
tile.setGeometry(1.0, 2.0, 0.1, 0.2, 107, 19);
tile.tileUpdateCompleted();
Assert.assertEquals(9, tile.getLevels()); Assert.assertEquals(9, tile.getLevels());
Field startField = MinMaxTreeTile.class.getDeclaredField("start"); Field startField = MinMaxTreeTile.class.getDeclaredField("start");
...@@ -62,9 +60,7 @@ public class MinMaxTreeTileTest { ...@@ -62,9 +60,7 @@ public class MinMaxTreeTileTest {
public void testSizeFat() public void testSizeFat()
throws RuggedException, SecurityException, NoSuchFieldException, throws RuggedException, SecurityException, NoSuchFieldException,
IllegalArgumentException, IllegalAccessException { IllegalArgumentException, IllegalAccessException {
MinMaxTreeTile tile = new MinMaxTreeTileFactory().createTile(); MinMaxTreeTile tile = createTile(4, 7);
tile.setGeometry(1.0, 2.0, 0.1, 0.2, 4, 7);
tile.tileUpdateCompleted();
Assert.assertEquals(4, tile.getLevels()); Assert.assertEquals(4, tile.getLevels());
Field startField = MinMaxTreeTile.class.getDeclaredField("start"); Field startField = MinMaxTreeTile.class.getDeclaredField("start");
...@@ -86,61 +82,100 @@ public class MinMaxTreeTileTest { ...@@ -86,61 +82,100 @@ public class MinMaxTreeTileTest {
@Test @Test
public void testSinglePixel() throws RuggedException { public void testSinglePixel() throws RuggedException {
MinMaxTreeTile tile = new MinMaxTreeTileFactory().createTile(); Assert.assertEquals(0, createTile(1, 1).getLevels());
tile.setGeometry(1.0, 2.0, 0.1, 0.2, 1, 1);
tile.setElevation(0, 0, 2.5);
tile.tileUpdateCompleted();
Assert.assertEquals(0, tile.getLevels());
} }
@Test @Test
public void testMinMax() throws RuggedException { public void testMinMax() throws RuggedException {
for (int nbRows = 1; nbRows < 25; nbRows++) { for (int nbRows = 1; nbRows < 25; nbRows++) {
for (int nbColumns = 1; nbColumns < 25; nbColumns++) { for (int nbColumns = 1; nbColumns < 25; nbColumns++) {
checkMinMax(nbRows, nbColumns);
MinMaxTreeTile tile = createTile(nbRows, nbColumns);
for (int level = 0; level < tile.getLevels(); level++) {
for (int row = 0; row < nbRows; row++) {
for (int column = 0; column < nbColumns; column++) {
// reference min and max
int[] neighbors = neighbors(row, column, nbRows, nbColumns, tile.getLevels() - level);
double min = Double.POSITIVE_INFINITY;
double max = Double.NEGATIVE_INFINITY;
for (int i = neighbors[0]; i < neighbors[1]; ++i) {
for (int j = neighbors[2]; j < neighbors[3]; ++j) {
double pixelValue = tile.getElevationAtIndices(i, j);
min = FastMath.min(min, pixelValue);
max = FastMath.max(max, pixelValue);
}
}
Assert.assertEquals(min, tile.getMinElevation(row, column, level), 1.0e-10 * min);
Assert.assertEquals(max, tile.getMaxElevation(row, column, level), 1.0e-10 * max);
}
}
}
} }
} }
} }
private void checkMinMax(int nbRows, int nbColumns) @Test
throws RuggedException { public void testMergeLarge() throws RuggedException {
MinMaxTreeTile tile = createTile(1201, 1201);
MinMaxTreeTile tile = new MinMaxTreeTileFactory().createTile(); Assert.assertEquals(21, tile.getLevels());
tile.setGeometry(1.0, 2.0, 0.1, 0.2, nbRows, nbColumns); Assert.assertEquals( 7, tile.getMergeLevel(703, 97, 765, 59));
for (int i = 0; i < nbRows; ++i) { }
for (int j = 0; j < nbColumns; ++j) {
tile.setElevation(i, j, i + 0.01 * j);
}
}
tile.tileUpdateCompleted();
for (int level = 0; level < tile.getLevels(); level++) { @Test
for (int row = 0; row < nbRows; row++) { public void testMergeLevel() throws RuggedException {
for (int column = 0; column < nbColumns; column++) { for (int nbRows = 1; nbRows < 20; nbRows++) {
for (int nbColumns = 1; nbColumns < 20; nbColumns++) {
// reference min and max
int[] neighbors = neighbors(row, column, nbRows, nbColumns, tile.getLevels() - level); MinMaxTreeTile tile = createTile(nbRows, nbColumns);
double min = Double.POSITIVE_INFINITY;
double max = Double.NEGATIVE_INFINITY; for (int i1 = 0; i1 < nbRows; i1++) {
for (int i = neighbors[0]; i < neighbors[1]; ++i) { for (int j1 = 0; j1 < nbColumns; j1++) {
for (int j = neighbors[2]; j < neighbors[3]; ++j) { for (int i2 = 0; i2 < nbRows; i2++) {
double pixelValue = tile.getElevationAtIndices(i, j); for (int j2 = 0; j2 < nbColumns; j2++) {
min = FastMath.min(min, pixelValue);
max = FastMath.max(max, pixelValue); int level = tile.getMergeLevel(i1, j1, i2, j2);
if (level > 0) {
int[] neighbors1 = neighbors(i1, j1, nbRows, nbColumns, tile.getLevels() - level);
int[] neighbors2 = neighbors(i2, j2, nbRows, nbColumns, tile.getLevels() - level);
for (int k = 0; k < neighbors1.length; ++k) {
Assert.assertTrue(neighbors1[0] == neighbors2[0] &&
neighbors1[1] == neighbors2[1] &&
neighbors1[2] == neighbors2[2] &&
neighbors1[3] == neighbors2[3]);
}
}
if (level + 1 < tile.getLevels()) {
int[] neighbors1 = neighbors(i1, j1, nbRows, nbColumns, tile.getLevels() - (level + 1));
int[] neighbors2 = neighbors(i2, j2, nbRows, nbColumns, tile.getLevels() - (level + 1));
for (int k = 0; k < neighbors1.length; ++k) {
if ((neighbors1[0] == neighbors2[0] &&
neighbors1[1] == neighbors2[1] &&
neighbors1[2] == neighbors2[2] &&
neighbors1[3] == neighbors2[3])) {
tile.getMergeLevel(i1, j1, i2, j2);
}
Assert.assertFalse(neighbors1[0] == neighbors2[0] &&
neighbors1[1] == neighbors2[1] &&
neighbors1[2] == neighbors2[2] &&
neighbors1[3] == neighbors2[3]);
}
}
}
} }
} }
Assert.assertEquals(min, tile.getMinElevation(row, column, level), 1.0e-10 * min);
Assert.assertEquals(max, tile.getMaxElevation(row, column, level), 1.0e-10 * max);
} }
} }
} }
} }
private int[] neighbors(int row, int column, int nbRows, int nbColumns, int stages) { private int[] neighbors(int row, int column, int nbRows, int nbColumns, int stages) {
// poor man identification of neighbors cells merged together with specified cell // poor man identification of neighbors cells merged together with specified cell
// this identification is intentionally independent of the MinMaxTreeTile class,
// for testing purposes
int rMin = row; int rMin = row;
int rN = 1; int rN = 1;
int rMask = -1; int rMask = -1;
...@@ -169,4 +204,16 @@ public class MinMaxTreeTileTest { ...@@ -169,4 +204,16 @@ public class MinMaxTreeTileTest {
} }
private MinMaxTreeTile createTile(int nbRows, int nbColumns) throws RuggedException {
MinMaxTreeTile tile = new MinMaxTreeTileFactory().createTile();
tile.setGeometry(1.0, 2.0, 0.1, 0.2, nbRows, nbColumns);
for (int i = 0; i < nbRows; ++i) {
for (int j = 0; j < nbColumns; ++j) {
tile.setElevation(i, j, i + 0.01 * j);
}
}
tile.tileUpdateCompleted();
return tile;
}
} }
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