use of org.apache.sis.coverage.SampleDimension in project sis by apache.
the class ConvertedGridCoverageTest method testForward.
/**
* Tests forward conversion from packed values to "geophysics" values.
* Test includes a conversion of an integer value to {@link Float#NaN}.
*/
@Test
public void testForward() {
/*
* A sample dimension with an identity transfer function
* except for value -1 which will be mapped to NaN.
*/
final SampleDimension sd = new SampleDimension.Builder().addQualitative(null, -1).addQuantitative("data", 0, 10, 1, 0, Units.UNITY).setName("data").build();
/*
* Creates an image of 2 pixels on a single row with sample values (-1, 3).
* The "grid to CRS" transform does not matter for this test.
*/
final GridGeometry grid = new GridGeometry(new GridExtent(2, 1), PixelInCell.CELL_CENTER, new AffineTransform2D(1, 0, 0, 1, 1, 0), HardCodedCRS.WGS84);
final BufferedGridCoverage coverage = new BufferedGridCoverage(grid, Collections.singletonList(sd), DataBuffer.TYPE_SHORT);
coverage.data.setElem(0, -1);
coverage.data.setElem(1, 3);
/*
* Verify values before and after conversion.
*/
assertValuesEqual(coverage.forConvertedValues(false).render(null), 0, new double[][] { { -1, 3 } });
final float nan = MathFunctions.toNanFloat(-1);
assertTrue(Float.isNaN(nan));
assertValuesEqual(coverage.forConvertedValues(true).render(null), 0, new double[][] { { nan, 3 } });
}
use of org.apache.sis.coverage.SampleDimension in project sis by apache.
the class BufferedGridCoverageTest method testMultidimensional.
/**
* Tests the creation of a three-dimensional coverage.
*/
@Test
public void testMultidimensional() {
final int width = 4;
final int height = 3;
final int nbTime = 3;
final GridExtent extent = new GridExtent(null, null, new long[] { width, height, nbTime }, false);
final GridGeometry domain = new GridGeometry(extent, PixelInCell.CELL_CENTER, MathTransforms.scale(2, 3, 5), null);
final SampleDimension band = new SampleDimension(Names.createLocalName(null, null, "Data"), null, Collections.emptyList());
/*
* Fill slices with all values set to 10, 11 and 12 at time t=0, 1 and 2 respectively.
* All values are stored in a single bank.
*/
final int sliceSize = width * height;
final int size = sliceSize * nbTime;
final int[] buffer = new int[size];
for (int t = 0, i = 0; t < nbTime; t++) {
Arrays.fill(buffer, i, i += sliceSize, t + 10);
}
final DataBufferInt data = new DataBufferInt(buffer, size);
final GridCoverage coverage = new BufferedGridCoverage(domain, Collections.singletonList(band), data);
/*
* Verify a value in each temporal slice.
*/
final int[] row10 = new int[width];
Arrays.fill(row10, 10);
final int[] row11 = new int[width];
Arrays.fill(row11, 11);
final int[] row12 = new int[width];
Arrays.fill(row12, 12);
assertRenderEqual(coverage, null, new long[] { width, height, 0 }, new int[][] { row10, row10, row10 });
assertRenderEqual(coverage, new long[] { 0, 0, 1 }, new long[] { width, height, 1 }, new int[][] { row11, row11, row11 });
assertRenderEqual(coverage, new long[] { 0, 0, 2 }, new long[] { width, height, 2 }, new int[][] { row12, row12, row12 });
assertRenderEqual(coverage, null, new long[] { width, 0, nbTime }, new int[][] { row10, row11, row12 });
assertRenderEqual(coverage, null, new long[] { 0, height, nbTime }, new int[][] { { 10, 10, 10 }, { 11, 11, 11 }, { 12, 12, 12 } });
}
use of org.apache.sis.coverage.SampleDimension in project sis by apache.
the class RenderingData method ensureImageLoaded.
/**
* Fetches the rendered image if {@linkplain #data} is null. This method needs to be invoked at least
* once after {@link #setCoverageSpace(GridGeometry, List)}. The {@code coverage} given in argument
* may be the value returned by {@link #ensureCoverageLoaded(LinearTransform, DirectPosition)}.
*
* @param coverage the coverage from which to read data, or {@code null} if the coverage did not changed.
* @param sliceExtent a subspace of the grid coverage extent where all dimensions except two have a size of 1 cell.
* May be {@code null} if this grid coverage has only two dimensions with a size greater than 1 cell.
* @return whether the {@linkpalin #data} changed.
* @throws FactoryException if the CRS changed but the transform from old to new CRS can not be determined.
* @throws TransformException if an error occurred while transforming coordinates from old to new CRS.
*/
public final boolean ensureImageLoaded(GridCoverage coverage, final GridExtent sliceExtent) throws FactoryException, TransformException {
if (data != null || coverage == null) {
return false;
}
coverage = coverage.forConvertedValues(true);
final GridGeometry old = dataGeometry;
final List<SampleDimension> ranges = coverage.getSampleDimensions();
final RenderedImage image = coverage.render(sliceExtent);
final Object value = image.getProperty(PlanarImage.GRID_GEOMETRY_KEY);
final GridGeometry domain = (value instanceof GridGeometry) ? (GridGeometry) value : new ImageRenderer(coverage, sliceExtent).getImageGeometry(BIDIMENSIONAL);
setCoverageSpace(domain, ranges);
data = image;
/*
* Update the transforms in a way that preserve the current zoom level, translation, etc.
* We compute the change in the "data grid to objective CRS" transforms caused by the change
* in data grid geometry, then we concatenate that change to the existing transforms.
* That way, the objective CRS is kept unchanged.
*/
if (old != null && cornerToObjective != null && objectiveToCenter != null) {
MathTransform toNew = null, toOld = null;
if (old.isDefined(GridGeometry.CRS) && domain.isDefined(GridGeometry.CRS)) {
final CoordinateReferenceSystem oldCRS = old.getCoordinateReferenceSystem();
final CoordinateReferenceSystem newCRS = dataGeometry.getCoordinateReferenceSystem();
if (newCRS != oldCRS) {
// Quick check for the vast majority of cases.
/*
* Transform computed below should always be the identity transform,
* but we check anyway as a safety. A non-identity transform would be
* a pyramid where the CRS changes according the pyramid level.
*/
final GeographicBoundingBox areaOfInterest = Extents.union(dataGeometry.getGeographicExtent().orElse(null), old.getGeographicExtent().orElse(null));
toNew = CRS.findOperation(oldCRS, newCRS, areaOfInterest).getMathTransform();
toOld = toNew.inverse();
}
}
final MathTransform forward = concatenate(PixelInCell.CELL_CORNER, dataGeometry, old, toOld);
final MathTransform inverse = concatenate(PixelInCell.CELL_CENTER, old, dataGeometry, toNew);
cornerToObjective = MathTransforms.concatenate(forward, cornerToObjective);
objectiveToCenter = MathTransforms.concatenate(objectiveToCenter, inverse);
}
return true;
}
use of org.apache.sis.coverage.SampleDimension in project sis by apache.
the class RasterReader method readAsCoverage.
/**
* Parses a raster from the given input stream and returns as a coverage.
*
* @param input source of bytes to read.
* @return the raster as a coverage, or {@code null} if the raster is empty.
* @throws Exception in an error occurred while reading from the given input or creating the coverage.
* Exception type may be I/O, SQL, factory, data store, arithmetic, raster format, <i>etc.</i>,
* too numerous for enumerating them all.
*/
public GridCoverage readAsCoverage(final ChannelDataInput input) throws Exception {
final BufferedImage image = readAsImage(input);
if (image == null) {
return null;
}
CoordinateReferenceSystem crs = null;
final int srid = getSRID();
if (spatialRefSys != null) {
crs = spatialRefSys.fetchCRS(srid);
} else if (srid > 0) {
crs = CRS.forCode(Constants.EPSG + ':' + srid);
}
if (crs == null) {
crs = defaultCRS;
}
final GridExtent extent = new GridExtent(image.getWidth(), image.getHeight());
final GridGeometry domain = new GridGeometry(extent, ANCHOR, getGridToCRS(), crs);
/*
* Create pseudo-categories with a transfer function if we need to specify "no data" value,
* or the sign of stored data do not match the sign of expected values.
*/
List<SampleDimension> range = null;
if (needsTransferFunction()) {
final SampleDimension[] sd = new SampleDimension[bands.length];
final SampleDimension.Builder builder = new SampleDimension.Builder();
for (int b = 0; b < sd.length; b++) {
final Band band = bands[b];
if ((band.getDataBufferType() & OPPOSITE_SIGN) != 0) {
// See `Band.OPPOSITE_SIGN` javadoc for more information on this limitation.
throw new RasterFormatException("Data type not yet supported.");
}
sd[b] = builder.setName(b + 1).setBackground(band.noDataValue).build();
builder.clear();
}
range = Arrays.asList(sd);
}
return new GridCoverage2D(domain, range, image);
}
use of org.apache.sis.coverage.SampleDimension in project sis by apache.
the class RasterWriter method setNodataValues.
/**
* Infers the "no data" values from the given sample dimensions.
* This method uses the {@linkplain SampleDimension#getBackground() background value} if available.
*
* @param bands the sample dimensions from which to infer the "no data" values.
*/
public void setNodataValues(final List<? extends SampleDimension> bands) {
noDataValues = new Number[bands.size()];
for (int b = 0; b < noDataValues.length; b++) {
final SampleDimension sd = bands.get(b);
noDataValues[b] = sd.getBackground().orElse(null);
}
}
Aggregations