You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2023/01/18 16:04:43 UTC
[sis-site] branch main updated: Add a "How to…" section with three first items.
This is an automated email from the ASF dual-hosted git repository.
desruisseaux pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/sis-site.git
The following commit(s) were added to refs/heads/main by this push:
new 9845d209 Add a "How to…" section with three first items.
9845d209 is described below
commit 9845d209a66ca0c431ca1de075e1396f2139823c
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Wed Jan 18 11:09:36 2023 +0100
Add a "How to…" section with three first items.
---
content/howto/_index.md | 11 ++
.../raster_values_at_geographic_coordinates.md | 185 +++++++++++++++++++++
content/howto/rasters_bigger_than_memory.md | 133 +++++++++++++++
content/howto/resample_and_save_raster.md | 147 ++++++++++++++++
layouts/_default/baseof.html | 1 +
layouts/partials/menu.html | 1 +
6 files changed, 478 insertions(+)
diff --git a/content/howto/_index.md b/content/howto/_index.md
new file mode 100644
index 00000000..ba3671f0
--- /dev/null
+++ b/content/howto/_index.md
@@ -0,0 +1,11 @@
+---
+title: How to
+---
+
+Java code examples for performing some tasks with Apache {{% SIS %}}.
+
+# Rasters
+
+* [Get raster values at geographic coordinates](howto/raster_values_at_geographic_coordinates.html)
+* [Handle rasters bigger than memory](howto/rasters_bigger_than_memory.html)
+* [Resample a raster and write to a file](howto/resample_and_save_raster.html)
diff --git a/content/howto/raster_values_at_geographic_coordinates.md b/content/howto/raster_values_at_geographic_coordinates.md
new file mode 100644
index 00000000..334f075d
--- /dev/null
+++ b/content/howto/raster_values_at_geographic_coordinates.md
@@ -0,0 +1,185 @@
+---
+title: Get raster values at geographic coordinates
+---
+
+This example reads a netCDF file and fetches values at given coordinates.
+The coordinates can be expressed in different Coordinate Reference System (CRS).
+Conversions from geographic coordinates to pixel coordinates,
+followed by conversions from raster data to units of measurement,
+are done automatically.
+Raster rata and spatiotemporal coordinates can have more than two dimensions.
+
+This example uses data in netCDF format.
+A netCDF file can contain an arbitrary amount of variables.
+For this reason, the data store implements the `Aggregate` interface
+and the desired variable must be specified.
+A similar code can be used for reading data in other
+formats supported by Apache {{% SIS %}} such as GeoTIFF,
+but not all formats are aggregates.
+For some file formats, the data store implements directly
+the `GridCoverageResource` interface instead of `Aggregate`.
+
+
+# Direct dependencies
+
+Maven coordinates | Module info | Remarks
+----------------------------------- | ------------------------------- | --------------------
+`org.apache.sis.storage:sis-netcdf` | `org.apache.sis.storage.netcdf` |
+`edu.ucar:cdm-core` | | For netCDF-4 or HDF5
+
+The `cdm-core` dependency can be omitted for netCDF-3 (a.k.a. "classic"),
+GeoTIFF or any other [formats supported by Apache SIS](../formats.html).
+For the dependencies required for reading GeoTIFF instead of netCDF files,
+see the [rasters bigger than memory](rasters_bigger_than_memory.html) snippet.
+
+
+# Code snippet
+
+The file name, resource name and geographic coordinates
+in following snippet need to be updated for yours data.
+
+{{< highlight java >}}
+import java.io.File;
+import java.util.Map;
+import javax.measure.Unit;
+import org.apache.sis.storage.Resource;
+import org.apache.sis.storage.Aggregate;
+import org.apache.sis.storage.DataStore;
+import org.apache.sis.storage.DataStores;
+import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.GridCoverageResource;
+import org.apache.sis.coverage.grid.GridCoverage;
+import org.apache.sis.geometry.GeneralDirectPosition;
+import org.apache.sis.referencing.CommonCRS;
+import org.apache.sis.measure.Units;
+
+public class RasterValuesAtGeographicCoordinates {
+ /**
+ * Demo entry point.
+ *
+ * @param args ignored.
+ * @throws DataStoreException if an error occurred while reading the raster.
+ */
+ public static void main(String[] args) throws DataStoreException {
+ try (DataStore store = DataStores.open(new File("CMEMS.nc"))) {
+ /*
+ * See what is inside this file. One of the components listed
+ * below can be given in argument to `findResource(String)`.
+ */
+ printComponents(store);
+ /*
+ * The following code read fully the specified resource.
+ * For reading only a subset, or for handling data bigger
+ * than memory, see "How to..." in Apache SIS web site.
+ */
+ Resource resource = store.findResource("sea_surface_height_above_geoid");
+ GridCoverage data = ((GridCoverageResource) resource).read(null, null);
+ System.out.printf("Information about the selected resource:%n%s%n", data);
+ /*
+ * Switch to a view of the data in the units of measurement.
+ * Then get the unit of measurement of the first band (0).
+ * If no unit is specified, fallback on dimensionless unit.
+ */
+ data = data.forConvertedValues(true);
+ int band = 0;
+ Unit<?> unit = data.getSampleDimensions().get(band).getUnits().orElse(Units.UNITY);
+ /*
+ * Get raster values at geographic coordinates expressed in WGS84.
+ * Coordinate values in this example are in (latitude, longitude) order.
+ * Any compatible coordinate reference system (CRS) can be used below,
+ * Apache SIS will automatically transform to the CRS used by the raster.
+ * If the raster data are three-dimensional, a 3D CRS should be specified.
+ */
+ System.out.println("Evaluation at some (latitude, longitude) coordinates:");
+ var point = new GeneralDirectPosition(CommonCRS.WGS84.geographic());
+ GridCoverage.Evaluator eval = data.evaluator();
+ /*
+ * If the data are three-dimensional but we still want to use two-dimensional
+ * coordinates, we need to specify a default value for the temporal dimension.
+ * This code set the default to slice 0 (the first slice) in dimension 2.
+ * Omit this line if the data are two-dimensional or if `point` has a 3D CRS.
+ */
+ eval.setDefaultSlice(Map.of(2, 0L));
+ /*
+ * The same `Evaluator` can be reused as often as needed for evaluating
+ * at many points.
+ */
+ point.setCoordinate(40, -10); // 40°N 10°W
+ double[] values = eval.apply(point);
+ System.out.printf("- Value at %s is %g %s.%n", point, values[band], unit);
+
+ point.setCoordinate(30, -15); // 30°N 15°W
+ values = eval.apply(point);
+ System.out.printf("- Value at %s is %g %s.%n", point, values[band], unit);
+ }
+ }
+
+ /**
+ * Lists the components found in the given data store.
+ * They are the values that can be given to {@link DataStore#findResource(String).
+ *
+ * @param store the data store from which to get the components.
+ * @throws DataStoreException if an error occurred while reading the raster.
+ */
+ private static void printComponents(DataStore store) throws DataStoreException {
+ if (store instanceof Aggregate a) {
+ System.out.println("Components found in the data store:");
+ for (Resource component : a.components()) {
+ component.getIdentifier().ifPresent((id) -> System.out.println("- " + id));
+ }
+ } else {
+ System.out.println("The data store is not an aggregate.");
+ }
+ System.out.println();
+ }
+}
+{{< / highlight >}}
+
+
+# Output
+
+The output depends on the raster data and the locale.
+Below is an example:
+
+```
+Components found in the data store:
+- sea_surface_height_above_geoid
+- sea_water_velocity
+
+Information about the selected resource:
+Raster
+ ├─Coverage domain
+ │ ├─Grid extent
+ │ │ ├─Column: [0 … 864] (865 cells)
+ │ │ ├─Row: [0 … 1080] (1081 cells)
+ │ │ └─Time: [0 … 95] (96 cells)
+ │ ├─Geographic extent
+ │ │ ├─Lower bound: 25°59′09″N 19°00′50″W 2022-05-16T00:00:00Z
+ │ │ └─Upper bound: 56°00′50″N 05°00′50″E 2022-05-17T00:00:00Z
+ │ ├─Envelope
+ │ │ ├─Geodetic longitude: -19.01388888888889 … 5.013888888888888 ∆Lon = 0.02777778°
+ │ │ ├─Geodetic latitude: 25.98611111111111 … 56.013888888888886 ∆Lat = 0.02777778°
+ │ │ └─time: 634,392.0 … 634,416.0 ∆t = 0.25 h
+ │ ├─Coordinate reference system
+ │ │ └─time latitude longitude
+ │ └─Conversion (origin in a cell center)
+ │ └─┌ ┐
+ │ │ 0.027777777777777776 0 0 -19.000 │
+ │ │ 0 0.027777777777777776 0 26.000 │
+ │ │ 0 0 0.25 634392.125 │
+ │ │ 0 0 0 1 │
+ │ └ ┘
+ └─Sample dimensions
+ └─┌────────────────────┬────────────────────────┬────────────────────┐
+ │ Values │ Measures │ Name │
+ ╞════════════════════╧════════════════════════╧════════════════════╡
+ │ zos │
+ ├────────────────────┬────────────────────────┬────────────────────┤
+ │ -32,767 │ NaN #0 │ Fill value │
+ │ [-10,000 … 10,000] │ [-10.0000 … 10.0000] m │ Sea surface height │
+ └────────────────────┴────────────────────────┴────────────────────┘
+
+Evaluation at some (latitude, longitude) coordinates:
+- Value at POINT(40 -10) is 0.188000 m.
+- Value at POINT(30 -15) is 0.619000 m.
+```
diff --git a/content/howto/rasters_bigger_than_memory.md b/content/howto/rasters_bigger_than_memory.md
new file mode 100644
index 00000000..c6d89544
--- /dev/null
+++ b/content/howto/rasters_bigger_than_memory.md
@@ -0,0 +1,133 @@
+---
+title: Handle rasters bigger than memory
+---
+
+This example opens a big GeoTIFF file without reading the tiles immediately.
+Instead, tiles will be read only when requested by a call to the Java2D `RenderedImage.getTile(int, int)` method.
+Loaded tiles are cached by soft references, i.e. they may be discarted and reloaded when needed again.
+This approach allows processing of raster data larger than memory,
+provided that the application does not request all tiles at once.
+It integrates well with operations provided by Apache {{% SIS %}} such as
+[raster resampling](resample_and_save_raster.html) and
+[getting values at geographic coordinates](raster_values_at_geographic_coordinates.html).
+
+The example in this page works with pixel coordinates.
+For working with geographic coordinates, see
+[values at geographic coordinates](raster_values_at_geographic_coordinates.html) snippet.
+
+
+# Direct dependencies
+
+Maven coordinates | Module info | Remarks
+------------------------------------------- | ------------------------------------- | -----------------------------
+`org.apache.sis.storage:sis-geotiff` | `org.apache.sis.storage.geotiff` |
+`org.apache.sis.non-free:sis-embedded-data` | `org.apache.sis.referencing.database` | Optional. Non-Apache license.
+
+The [EPSG dependency](../epsg.html) may or may not be needed,
+depending how the Coordinate Reference System (CRS) is encoded in the GeoTIFF file.
+
+
+# Code snippet
+
+The file name in following snippet need to be updated for yours data.
+
+{{< highlight java >}}
+import java.io.File;
+import java.util.Collection;
+import java.awt.Rectangle;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.image.ImagingOpException;
+import org.apache.sis.image.ImageProcessor;
+import org.apache.sis.storage.Resource;
+import org.apache.sis.storage.Aggregate;
+import org.apache.sis.storage.DataStore;
+import org.apache.sis.storage.DataStores;
+import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.GridCoverageResource;
+import org.apache.sis.storage.RasterLoadingStrategy;
+import org.apache.sis.coverage.grid.GridCoverage;
+
+public class RasterBiggerThanMemory {
+ /**
+ * Demo entry point.
+ *
+ * @param args ignored.
+ * @throws DataStoreException if an error occurred while reading the raster.
+ * @throws ImagingOpException unchecked exception thrown if an error occurred while loading a tile.
+ */
+ public static void main(String[] args) throws DataStoreException {
+ try (DataStore store = DataStores.open(new File("TM250m.tiff"))) {
+ /*
+ * This data store is an aggregate because a GeoTIFF file may contain many images.
+ * Not all data stores are aggregate, so the following casts do not apply to all.
+ * For this example, we know that the file is GeoTIFF and we take the first image.
+ */
+ Collection<? extends Resource> allImages = ((Aggregate) store).components();
+ GridCoverageResource firstImage = (GridCoverageResource) allImages.iterator().next();
+ /*
+ * Following line requests to load data at `RenderedImage.getTile(…)` invocation time.
+ * This is the key line of code for handling rasters larger than memory, but is effective
+ * only if the file is tiled as in, for example, Cloud Optimized GeoTIFF (COG) convention.
+ * Without this line, the default is to load all data at `GridCoverageResource.read(…)`
+ * invocation time.
+ */
+ firstImage.setLoadingStrategy(RasterLoadingStrategy.AT_GET_TILE_TIME);
+ GridCoverage data = firstImage.read(null, null);
+ System.out.printf("Information about the selected image:%n%s%n", data);
+ /*
+ * Get an arbitrary tile, then get an arbitrary sample value in an arbitrary band
+ * (the blue channel) of that tile.
+ */
+ RenderedImage image = data.render(null);
+ System.out.printf("The image has %d × %d tiles.%n", image.getNumXTiles(), image.getNumYTiles());
+
+ Raster tile = image.getTile(130, 80); // This is where tile loading actually happen.
+ System.out.printf("Got a tile starting at coordinates %d, %d.%n", tile.getMinX(), tile.getMinY());
+ System.out.printf("A sample value in a tile: %d%n", tile.getSample(93710, 57680, 2));
+ /*
+ * If we know in advance which tiles will be requested, specifying them in advance allows
+ * the GeoTIFF reader to use a better strategy than loading the tiles in random order.
+ */
+ var processor = new ImageProcessor();
+ image = processor.prefetch(image, new Rectangle(90000, 50000, 1000, 1000));
+ tile = image.getTile(130, 80);
+ System.out.printf("Same, but from prefetched image: %d%n%n", tile.getSample(93710, 57680, 2));
+ }
+ }
+}
+{{< / highlight >}}
+
+
+# Output
+
+The output depends on the raster data and the locale.
+Below is an example:
+
+```
+Information about the selected image:
+CompressedSubset
+ └─Coverage domain
+ ├─Grid extent
+ │ ├─Column: [0 … 172799] (172800 cells)
+ │ └─Row: [0 … 86399] (86400 cells)
+ ├─Geographic extent
+ │ ├─Lower bound: 90°00′00″S 180°00′00″W
+ │ └─Upper bound: 90°00′00″N 180°00′00″E
+ ├─Envelope
+ │ ├─Geodetic longitude: -180.000 … 180.000 ∆Lon = 0.00208333°
+ │ └─Geodetic latitude: -90.000 … 90.000 ∆Lat = 0.00208333°
+ ├─Coordinate reference system
+ │ └─CRS:84 — WGS 84
+ └─Conversion (origin in a cell center)
+ └─┌ ┐
+ │ 0.0020833333333333333 0 -179.99895833333332 │
+ │ 0 -0.0020833333333333333 89.99895833333333 │
+ │ 0 0 1 │
+ └ ┘
+
+The image has 240 × 120 tiles.
+Got a tile starting at coordinates 93600, 57600.
+A sample value in a tile: 20
+Same, but from prefetched image: 20
+```
diff --git a/content/howto/resample_and_save_raster.md b/content/howto/resample_and_save_raster.md
new file mode 100644
index 00000000..039299ff
--- /dev/null
+++ b/content/howto/resample_and_save_raster.md
@@ -0,0 +1,147 @@
+---
+title: Resample a raster and write to a file
+---
+
+This example reads a raster in a GeoTIFF file
+and reprojects it to a different Coordinate Reference System (CRS).
+The result is saved as a World File in PNG format.
+
+
+# Direct dependencies
+
+Maven coordinates | Module info | Remarks
+------------------------------------------- | ------------------------------------- | -----------------------------
+`org.apache.sis.storage:sis-geotiff` | `org.apache.sis.storage.geotiff` |
+`org.apache.sis.non-free:sis-embedded-data` | `org.apache.sis.referencing.database` | Non-Apache license.
+
+The [EPSG dependency](../epsg.html) is necessary for this example
+because a Coordinate Reference System (CRS) is instantiated from its EPSG code.
+But it would also be possible to specify a CRS without EPSG code,
+for example using Well Known Text (WKT) format.
+
+
+# Code snippet
+
+The file name in following snippet need to be updated for yours data.
+
+{{< highlight java >}}
+import java.nio.file.Paths;
+import java.util.Collection;
+import java.awt.image.ImagingOpException;
+import org.apache.sis.storage.Resource;
+import org.apache.sis.storage.Aggregate;
+import org.apache.sis.storage.DataStore;
+import org.apache.sis.storage.DataStores;
+import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.GridCoverageResource;
+import org.apache.sis.coverage.grid.GridCoverage;
+import org.apache.sis.coverage.grid.GridCoverageProcessor;
+import org.apache.sis.image.Interpolation;
+import org.apache.sis.referencing.CRS;
+import org.opengis.referencing.operation.TransformException;
+import org.opengis.util.FactoryException;
+
+public class ResampleAndSaveRaster {
+ /**
+ * Demo entry point.
+ *
+ * @param args ignored.
+ * @throws DataStoreException if an error occurred while reading the raster.
+ * @throws FactoryException if an error occurred while creating the Coordinate Reference System (CRS).
+ * @throws TransformException if an error occurred while transforming coordinates to the target CRS.
+ * @throws ImagingOpException unchecked exception thrown if an error occurred while resampling a tile.
+ */
+ public static void main(String[] args) throws DataStoreException, FactoryException, TransformException {
+ try (DataStore store = DataStores.open(Paths.get("Airport.tiff"))) {
+ /*
+ * This data store is an aggregate because a GeoTIFF file may contain many images.
+ * Not all data stores are aggregate, so the following casts do not apply to all.
+ * For this example, we know that the file is GeoTIFF and we take the first image.
+ */
+ Collection<? extends Resource> allImages = ((Aggregate) store).components();
+ GridCoverageResource firstImage = (GridCoverageResource) allImages.iterator().next();
+ /*
+ * The following code read fully the specified resource.
+ * For reading only a subset, or for handling data bigger
+ * than memory, see "How to..." in Apache SIS web site.
+ */
+ GridCoverage data = firstImage.read(null, null);
+ System.out.printf("Information about the selected image:%n%s%n", data);
+ /*
+ * Reproject to "WGS 84 / World Mercator" (EPSG::3395) using bilinear interpolation.
+ * This example lets Apache SIS choose the output grid size and resolution.
+ * But it is possible to specify those aspects if desired.
+ */
+ var processor = new GridCoverageProcessor();
+ processor.setInterpolation(Interpolation.BILINEAR);
+ data = processor.resample(data, CRS.forCode("EPSG::3395"));
+ System.out.printf("Information about the image after reprojection:%n%s%n", data);
+ /*
+ * TODO: Apache SIS is missing an `DataStores.write(…)` convenience method.
+ * Writing a TIFF World File is possible but requires use of internal API.
+ * A public convenience method will be added in next version.
+ */
+ }
+ }
+}
+{{< / highlight >}}
+
+
+# Output
+
+The output depends on the raster data and the locale.
+Below is an example:
+
+```
+Information about the image after reprojection:
+GridCoverage2D
+ ├─Coverage domain
+ │ ├─Grid extent
+ │ │ ├─Column: [0 … 8191] (8192 cells)
+ │ │ └─Row: [0 … 8191] (8192 cells)
+ │ ├─Geographic extent
+ │ │ ├─Lower bound: 48°59′20″N 02°31′33″E
+ │ │ └─Upper bound: 49°01′08″N 02°34′16″E
+ │ ├─Envelope
+ │ │ ├─Easting: 465,341.6 … 468,618.39999999997 ∆E = 0.4 m
+ │ │ └─Northing: 5,426,352.8 … 5,429,629.6 ∆N = 0.4 m
+ │ ├─Coordinate reference system
+ │ │ └─EPSG:32631 — WGS 84 / UTM zone 31N
+ │ └─Conversion (origin in a cell center)
+ │ └─┌ ┐
+ │ │ 0.4 0 465341.8 │
+ │ │ 0 -0.4 5429629.4 │
+ │ │ 0 0 1 │
+ │ └ ┘
+ └─Image layout
+ ├─Origin: 0, 0
+ ├─Tile size: 8,192 × 128
+ ├─Data type: byte
+ └─Image is opaque.
+
+Information about the image after reprojection:
+GridCoverage2D
+ ├─Coverage domain
+ │ ├─Grid extent
+ │ │ ├─Dimension 0: [0 … 8239] (8240 cells)
+ │ │ └─Dimension 1: [0 … 8240] (8241 cells)
+ │ ├─Geographic extent
+ │ │ ├─Lower bound: 48°59′20″N 02°31′33″E
+ │ │ └─Upper bound: 49°01′08″N 02°34′16″E
+ │ ├─Envelope
+ │ │ ├─Easting: 281,190.4273301751 … 286,207.11249780044 ∆E = 0.60882102 m
+ │ │ └─Northing: 6,240,752.860382801 … 6,245,770.154371441 ∆N = 0.60882102 m
+ │ ├─Coordinate reference system
+ │ │ └─EPSG:3395 — WGS 84 / World Mercator
+ │ └─Conversion (origin in a cell center)
+ │ └─┌ ┐
+ │ │ 0.6088210154885099 0 281190.73174068285 │
+ │ │ 0 -0.60882101548851 6245769.8499609330 │
+ │ │ 0 0 1 │
+ │ └ ┘
+ └─Image layout
+ ├─Origin: 0, 0
+ ├─Tile size: 1,648 × 201
+ ├─Data type: byte
+ └─Image is opaque.
+```
diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html
index c3b8ed2d..06911070 100644
--- a/layouts/_default/baseof.html
+++ b/layouts/_default/baseof.html
@@ -37,6 +37,7 @@
<li><a class="nav-link {{ if eq .Page.RelPermalink "/" }} active {{ else }} text-white {{ end }}" href="/index.html">Home</a></li>
<li><a class="nav-link text-white" href="http://www.apache.org/licenses/">License</a></li>
<li><a class="nav-link {{ if eq .Page.RelPermalink "/downloads.html" }} active {{ else }} text-white {{ end }}" href="/downloads.html">Downloads</a></li>
+ <li><a class="nav-link {{ if strings.Contains .Page.RelPermalink "/howto" }} active {{ else }} text-white {{ end }}" href="/howto.html">How to…</a></li>
<li><a class="nav-link {{ if eq .Page.RelPermalink "/standards.html" }} active {{ else }} text-white {{ end }}" href="/standards.html">Standards</a></li>
<li><a class="nav-link {{ if eq .Page.RelPermalink "/formats.html" }} active {{ else }} text-white {{ end }}" href="/formats.html">Data formats</a></li>
<li><a class="nav-link {{ if eq .Page.RelPermalink "/epsg.html" }} active {{ else }} text-white {{ end }}" href="/epsg.html">EPSG Database</a></li>
diff --git a/layouts/partials/menu.html b/layouts/partials/menu.html
index e3f52afe..14337b90 100644
--- a/layouts/partials/menu.html
+++ b/layouts/partials/menu.html
@@ -24,6 +24,7 @@
<ul class="dropdown-menu" aria-labelledby="menuDocumentation">
<li><a class="dropdown-item" href="/apidocs/index.html">Online Javadoc</a></li>
<li><a class="dropdown-item" href="/book/en/developer-guide.html">Developer Guide</a></li>
+ <li><a class="dropdown-item" href="/howto.html">How to…</a></li>
<li><a class="dropdown-item" href="/formats.html">Supported formats</a></li>
<li><a class="dropdown-item" href="/tables/CoordinateReferenceSystems.html">Supported CRS</a></li>
<li><a class="dropdown-item" href="/tables/CoordinateOperationMethods.html">Map Projections</a></li>