/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2009-2012, Open Source Geospatial Foundation (OSGeo)
* (C) 2009-2012, Geomatys
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotoolkit.image.io.mosaic;
import java.awt.Rectangle;
import java.awt.Dimension;
import java.io.IOException;
import org.apache.sis.math.Statistics;
import org.junit.*;
import static org.junit.Assert.*;
/**
* Tests the {@link MosaicProfiler} using the Blue Marble mosaic.
*
* @author Martin Desruisseaux (Geomatys)
* @version 3.00
*
* @since 3.00
*/
public final strictfp class MosaicProfilerTest extends MosaicTestBase {
/**
* Small value for floating point comparisons.
*/
private static final double EPS = 1E-10;
/**
* Ensures that the {@code min} size is not greater than {@code max}.
*/
private static void assertNotGreater(final Dimension min, final Dimension max) {
assertTrue("Width is out of bounds.", min.width <= max.width);
assertTrue("Height is out of bounds.", min.height <= max.height);
}
/**
* Run a single sample using the given profiler, and returns the estimated cost.
*
* @param profiler The profiler for which to run {@link MosaicProfiler#estimateEfficiency(int)}.
* @return The efficiency estimation.
* @throws IOException Should not happen.
*/
private static double single(final MosaicProfiler profiler) throws IOException {
final Statistics stats = profiler.estimateEfficiency(1);
assertEquals(1, stats.count());
return stats.mean();
}
/**
* Tests {@link MosaicProfiler#estimateEfficiency(int)} with some pre-defined regions
* and subsampling values. Note that because we leave no room for random values,
* the random seed should have no effect.
* <p>
* The pyramid used have subsamplings of 1,3,5,9,15,45,90. It has no subsampling
* of 2, which is useful for this test.
*
* @throws IOException Should not happen.
*/
@Test
public void testExactTileSize() throws IOException {
final MosaicProfiler profiler = new MosaicProfiler(manager);
profiler.setMinSize(TARGET_SIZE);
profiler.setMaxSize(TARGET_SIZE);
/*
* Tests images having exactly the size of tiles with no subsampling.
*/
profiler.setMaxSubsampling(1);
final Rectangle region = new Rectangle(2*TARGET_SIZE, 3*TARGET_SIZE, TARGET_SIZE, TARGET_SIZE);
profiler.setQueryRegion(region);
assertEquals("Asking for an exact tile should have no cost.", 1, single(profiler), EPS);
region.translate(TARGET_SIZE/4, 0);
profiler.setQueryRegion(region);
assertEquals("Asked a translated images requerying 2 tiles.", 0.5, single(profiler), EPS);
region.translate(0, TARGET_SIZE*3/4);
profiler.setQueryRegion(region);
assertEquals("Asked a translated images requerying 4 tiles.", 0.25, single(profiler), EPS);
/*
* Tests images twice bigger, with a subsampling of 2. Because there is no such subsampling
* in the pyramid used for this test, it should fallback on the subsampling of 1.
*/
profiler.setMinSubsampling(2);
assertEquals("MaxSubsampling should have been adjusted automatically.",
new Dimension(2, 2), profiler.getMaxSubsampling());
region.x = region.y = TARGET_SIZE*4;
region.width = region.height = TARGET_SIZE*2;
profiler.setQueryRegion(region);
assertEquals("Asking for an exact tile should have no cost.", 0.25, single(profiler), EPS);
region.translate(TARGET_SIZE, TARGET_SIZE);
profiler.setQueryRegion(region);
assertEquals("Cost should stay the same.", 0.25, single(profiler), EPS);
region.translate(TARGET_SIZE/4, TARGET_SIZE*3/4);
profiler.setQueryRegion(region);
assertEquals("Asked an images requerying more tiles.", 1./9, single(profiler), EPS);
/*
* Tests images with a subsampling of 3. We should be back on a subsampling
* handled by the pyramid.
*/
profiler.setMinSubsampling(3);
assertEquals("MaxSubsampling should have been adjusted automatically.",
new Dimension(3, 3), profiler.getMaxSubsampling());
region.x = region.y = TARGET_SIZE*6;
region.width = region.height = TARGET_SIZE*3;
profiler.setQueryRegion(region);
assertEquals("Asking for an exact tile should have no cost.", 1, single(profiler), EPS);
region.translate(TARGET_SIZE, TARGET_SIZE);
profiler.setQueryRegion(region);
assertEquals("Asked a translated images requerying 4 tiles.", 0.25, single(profiler), EPS);
}
/**
* Tests {@link MosaicProfiler#estimateEfficiency(int)} for a constant image size and
* using increasing subsampling values.
*
* @throws IOException Should not happen.
*/
@Test
public void testEfficiencyAtConstantSubsampling() throws IOException {
final MosaicProfiler profiler = new MosaicProfiler(manager);
assertNotGreater(profiler.getMaxSize(), profiler.getMosaicSize());
profiler.setSeed(897026254);
profiler.setMinSize(new Dimension(800, 600));
profiler.setMaxSize(new Dimension(800, 600));
profiler.setMaxSubsampling(1);
final double[] strict = new double[50];
final double[] better = new double[strict.length];
for (int i=0; i<strict.length; i++) {
profiler.setMinSubsampling(i + 1);
strict[i] = profiler.estimateEfficiency(50).mean();
}
profiler.setSeed(897026254);
profiler.setMaxSubsampling(1);
profiler.setSubsamplingChangeAllowed(true);
for (int i=0; i<better.length; i++) {
profiler.setMinSubsampling(i + 1);
better[i] = profiler.estimateEfficiency(50).mean();
}
/*
* Empirical values determined from previous run of this test. This test is performed only
* in order to avoid regression; it doesn't not guarantee that the values are correct (this
* was the job of the previous test methods). For updating the empirical values, set the
* "if (false)" statement to "if (true)" in the block below. The columns are:
*
* - cost when subsampling change is not allowed
* - cost when subsampling changes are allowed.
* - Ratio betwen column 1 and column 2
* - The subsampling value.
*/
if (false) {
for (int i=0; i<strict.length; i++) {
System.out.println(String.format(java.util.Locale.US,
"%6.3f, %6.3f, // %6.2f [%2d]",
strict[i], better[i], better[i] / strict[i], i+1));
}
}
final double[] expected = {
0.203, 0.203, // 1.00 [ 1]
0.088, 0.088, // 1.00 [ 2]
0.180, 0.180, // 1.00 [ 3]
0.036, 0.270, // 7.54 [ 4]
0.206, 0.206, // 1.00 [ 5]
0.088, 0.240, // 2.73 [ 6]
0.014, 0.267, // 18.86 [ 7]
0.011, 0.291, // 25.59 [ 8]
0.214, 0.214, // 1.00 [ 9]
0.100, 0.219, // 2.19 [10]
0.007, 0.249, // 38.18 [11]
0.036, 0.269, // 7.54 [12]
0.005, 0.279, // 58.06 [13]
0.004, 0.321, // 75.49 [14]
0.247, 0.247, // 1.00 [15]
0.003, 0.261, // 78.99 [16]
0.003, 0.258, // 86.74 [17]
0.099, 0.255, // 2.57 [18]
0.002, 0.291, // 121.63 [19]
0.036, 0.281, // 7.77 [20]
0.015, 0.286, // 19.51 [21]
0.002, 0.263, // 142.85 [22]
0.002, 0.294, // 175.34 [23]
0.011, 0.282, // 25.15 [24]
0.025, 0.313, // 12.78 [25]
0.001, 0.333, // 249.32 [26]
0.054, 0.368, // 6.79 [27]
0.001, 0.367, // 318.13 [28]
0.001, 0.354, // 327.02 [29]
0.101, 0.101, // 1.00 [30]
0.001, 0.102, // 106.91 [31]
0.001, 0.107, // 119.17 [32]
0.007, 0.111, // 16.84 [33]
0.001, 0.102, // 127.94 [34]
0.015, 0.106, // 7.20 [35]
0.037, 0.115, // 3.12 [36]
0.001, 0.118, // 173.21 [37]
0.001, 0.117, // 180.79 [38]
0.005, 0.126, // 25.91 [39]
0.012, 0.132, // 11.52 [40]
0.001, 0.113, // 203.96 [41]
0.004, 0.119, // 28.25 [42]
0.001, 0.122, // 239.92 [43]
0.000, 0.126, // 258.68 [44]
0.286, 0.286, // 1.00 [45]
0.000, 0.321, // 715.46 [46]
0.000, 0.352, // 824.85 [47]
0.003, 0.356, // 107.57 [48]
0.000, 0.358, // 913.88 [49]
0.008, 0.354, // 45.91 [50]
};
for (int i=0,j=0; j<expected.length; i++) {
assertEquals("strict", expected[j++], strict[i], 0.001);
assertEquals("better", expected[j++], better[i], 0.001);
}
}
}