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 bea3f1ff Move "How to" items in the FAQ as pages in the "How to" directory. bea3f1ff is described below commit bea3f1ffaabb38d0fe7a33b01c14f9b009de19fe Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Sat Jan 21 00:15:54 2023 +0100 Move "How to" items in the FAQ as pages in the "How to" directory. --- content/faq.md | 166 +++++---------------- content/howto/_index.md | 15 +- content/howto/crs_equality.md | 73 +++++++++ content/howto/instantiate_utm_projection.md | 91 +++++++++++ content/howto/lookup_crs_urn.md | 95 ++++++++++++ .../raster_values_at_geographic_coordinates.md | 6 +- content/howto/rasters_bigger_than_memory.md | 6 +- content/howto/resample_and_save_raster.md | 13 +- content/howto/transform_coordinates.md | 86 +++++++++++ 9 files changed, 408 insertions(+), 143 deletions(-) diff --git a/content/faq.md b/content/faq.md index 2e3b2fc1..0edd04a1 100644 --- a/content/faq.md +++ b/content/faq.md @@ -10,41 +10,21 @@ This page lists some Frequently Asked Questions (FAQ) when using Apache {{% SIS ## Getting started {#referencing-intro} +### How do I get a Coordinate Reference System? {#getCRS} + +The `CRS` class in the `org.apache.sis.referencing.crs` package provides static convenience methods. +The most notable methods are: + +* `CRS.forCode(String)` for fetching a {{% CRS %}} from an authority code in a database. + Some supported authorities are [EPSG](epsg.html), AUTO, AUTO2 and CRS. +* `CRS.fromWKT(String)` for parsing a {{% CRS %}} definition from a character string in Well-Known Text (WKT) format. +* `CRS.fromXML(String)` for parsing a {{% CRS %}} definition from a character string in Geographic Markup Language (GML) format. + ### How do I transform a coordinate? {#transform-point} -The following Java code projects a geographic coordinate from the _World Geodetic System 1984_ (WGS84) to _WGS 84 / UTM zone 33N_. -In order to make the example a little bit simpler, this code uses predefined constants given by the `CommonCRS` convenience class. -But more advanced applications will typically use EPSG codes instead. -Note that all geographic coordinates below express latitude *before* longitude. - - {{< highlight java >}} -import org.opengis.geometry.DirectPosition; -import org.opengis.referencing.crs.CoordinateReferenceSystem; -import org.opengis.referencing.operation.CoordinateOperation; -import org.opengis.referencing.operation.TransformException; -import org.opengis.util.FactoryException; -import org.apache.sis.referencing.CRS; -import org.apache.sis.referencing.CommonCRS; -import org.apache.sis.geometry.DirectPosition2D; - -public class MyApp { - public static void main(String[] args) throws FactoryException, TransformException { - CoordinateReferenceSystem sourceCRS = CommonCRS.WGS84.geographic(); - CoordinateReferenceSystem targetCRS = CommonCRS.WGS84.universal(40, 14); // Get whatever zone is valid for 14°E. - CoordinateOperation operation = CRS.findOperation(sourceCRS, targetCRS, null); - /* - * The above lines are costly and should be performed only once before to project many points. - * In this example, the operation that we got is valid for coordinates in geographic area from - * 12°E to 18°E (UTM zone 33) and 0°N to 84°N. - */ - DirectPosition ptSrc = new DirectPosition2D(40, 14); // 40°N 14°E - DirectPosition ptDst = operation.getMathTransform().transform(ptSrc, null); - - System.out.println("Source: " + ptSrc); - System.out.println("Target: " + ptDst); - } -} -{{< / highlight >}} +See the ["How to…"](howto.html#referencing) page for Java code examples. +Those examples get Coordinate Reference Systems (CRS) instances in various ways +and apply coordinate operations between two reference systems. ### Which map projections are supported? {#operation-methods} @@ -61,6 +41,27 @@ A well-known source of such definitions is the EPSG geodetic dataset, but other The predefined {{% CRS %}} known to Apache {{% SIS %}} are listed in the [Coordinate Reference Systems](tables/CoordinateReferenceSystems.html) page. +## Coordinate Reference Systems {#crs} + +### What is the Google projection? {#google} + +The Google projection is a Mercator projection that pretends to be defined on the WGS84 datum, +but actually ignores the ellipsoidal nature of that datum and uses the simpler spherical formulas instead. +Since version 6.15 of EPSG geodetic dataset, the preferred way to get that projection is to invoke `CRS.forCode("EPSG:3857")`. +Note that the use of that projection is **not** recommended, unless needed for compatibility with other data. + +The EPSG:3857 definition uses a map projection method named _"Popular Visualisation Pseudo Mercator"_. +The EPSG geodetic dataset provides also some other map projections that use spherical formulas. +Those methods have "(Spherical)" in their name, for example _"Mercator (Spherical)"_, +and differs from _"Popular Visualisation Pseudo Mercator"_ by the use of a more appropriate sphere radius. +Those projection methods can be used in Well Known Text (WKT) definitions. + +If there is a need to use spherical formulas with a projection that does not have a spherical counterpart, +this can be done with explicit declarations of `"semi_major"` and `"semi_minor"` parameter values in the {{% WKT %}} definition. +Those parameter values are usually inferred from the datum, but Apache {{% SIS %}} allows explicit declarations to override the inferred values. +This hack is provided for making possible to use data that ignore the ellipsoid flattening factor +(which are unfortunately not uncommon), but it should be used in last resort only. + ### What is the axis order issue and how is it addressed? {#axisOrder} The axis order is specified by the authority (typically a national agency) defining the Coordinate Reference System (CRS). @@ -97,99 +98,6 @@ CoordinateReferenceSystem crs = ...; // CRS obtained by any means. crs = AbstractCRS.castOrCopy(crs).forConvention(AxesConvention.RIGHT_HANDED) {{< / highlight >}} -## Coordinate Reference Systems {#crs} - -### How do I instantiate a Universal Transverse Mercator (UTM) projection? {#UTM} - -If the UTM zone is unknown, an easy way is to invoke the `universal(…)` method on one of the `CommonCRS` predefined constants. -That method receives in argument a geographic coordinate in (_latitude_, _longitude_) order and computes the UTM zone from it. -See the [above Java code example](#transform-point). - -If the UTM zone is know, one way is to use the "EPSG" or "AUTO" authority factory. -The EPSG code of some UTM projections can be determined as below, where _zone_ is a number from 1 to 60 inclusive (unless otherwise specified): - -* WGS 84 (northern hemisphere): 32600 + _zone_ -* WGS 84 (southern hemisphere): 32700 + _zone_ -* WGS 72 (northern hemisphere): 32200 + _zone_ -* WGS 72 (southern hemisphere): 32300 + _zone_ -* NAD 83 (northern hemisphere): 26900 + _zone_ (zone 1 to 23 only) -* NAD 27 (northern hemisphere): 26700 + _zone_ (zone 1 to 22 only) - -Note that the above list is incomplete. See the EPSG database for additional UTM definitions -(WGS 72BE, SIRGAS 2000, SIRGAS 1995, SAD 69, ETRS 89, _etc._, most of them defined only for a few zones). -Once the EPSG code of the UTM projection has been determined, the {{% CRS %}} can be obtained as in the example below: - -{{< highlight java >}} -int code = 32600 + zone; // For WGS84 northern hemisphere -CoordinateReferenceSystem crs = CRS.forCode("EPSG:" + code); -{{< / highlight >}} - -### How do I instantiate a Google projection? {#google} - -The Google projection is a Mercator projection that pretends to be defined on the WGS84 datum, -but actually ignores the ellipsoidal nature of that datum and uses the simpler spherical formulas instead. -Since version 6.15 of EPSG geodetic dataset, the preferred way to get that projection is to invoke `CRS.forCode("EPSG:3857")`. -Note that the use of that projection is **not** recommended, unless needed for compatibility with other data. - -The EPSG:3857 definition uses a map projection method named _"Popular Visualisation Pseudo Mercator"_. -The EPSG geodetic dataset provides also some other map projections that use spherical formulas. -Those methods have "(Spherical)" in their name, for example _"Mercator (Spherical)"_ -(which differs from _"Popular Visualisation Pseudo Mercator"_ by the use of a more appropriate sphere radius). -Those projection methods can be used in Well Known Text (WKT) definitions. - -If there is a need to use spherical formulas with a projection that does not have a "(Spherical)" counterpart, -this can be done with explicit declarations of `"semi_major"` and `"semi_minor"` parameter values in the {{% WKT %}} definition. -Those parameter values are usually inferred from the datum, but Apache {{% SIS %}} allows explicit declarations to override the inferred values. - -### How can I identify the projection kind of a CRS? {#projectionKind} - -The "kind of projection" (Mercator, Lambert Conformal, _etc._) is called _Operation Method_ in {{% ISO %}} 19111 terminology. -One approach is to check the value of `OperationMethod.getName()` and compare them against the {{% OGC %}} or EPSG names -listed in the [Coordinate Operation Methods](tables/CoordinateOperationMethods.html) page. - -### How do I get the EPSG code of an existing CRS? {#lookupEPSG} - -The _identifier_ of a Coordinate Reference System (CRS) object can be obtained by the `getIdentifiers()` method, -which usually return a collection of zero or one element. -If the {{% CRS %}} has been created from a Well Known Text (WKT) parsing -and the {{% WKT %}} ends with an `AUTHORITY["EPSG", "xxxx"]` ({{% WKT %}} version 1) -or `ID["EPSG", xxxx]` ({{% WKT %}} version 2) element, -then the identifier (an EPSG numerical code in this example) is the _xxxx_ value in that element. -If the {{% CRS %}} has been created from the EPSG geodetic dataset (for example by a call to `CRS.forCode("EPSG:xxxx")`), -then the identifier is the _xxxx_ code given to that method. -If the {{% CRS %}} has been created in another way, then the collection returned by the `getIdentifiers()` method -may or may not be empty depending if the program that created the {{% CRS %}} took the responsibility of providing identifiers. - -If the collection of identifiers is empty, the most effective fix is to make sure that the {{% WKT %}} -contains an `AUTHORITY` or `ID` element (assuming that the {{% CRS %}} was parsed from a {{% WKT %}}). -If this is not possible, then the `org.apache.sis.referencing.IdentifiedObjects` class contains some convenience methods which may help. -In the following example, the call to `lookupEPSG(…)` will scan the EPSG database for a {{% CRS %}} equals -(ignoring metadata) to the given one. *Note that this scan is sensitive to axis order.* -Most geographic {{% CRS %}} in the EPSG database are declared with (_latitude_, _longitude_) axis order. -Consequently if the given {{% CRS %}} has (_longitude_, _latitude_) axis order, then the scan is likely to find no match. - -{{< highlight java >}} -CoordinateReferenceSystem myCRS = ...; -Integer identifier = IdentifiedObjects.lookupEPSG(myCRS); -if (identifier != null) { - System.out.println("The EPSG code has been found: " + identifier); -} -{{< / highlight >}} - -### How do I get the "urn:ogc:def:crs:…" URN of an existing CRS? {#lookupURN} - -{{% OGC %}} defines URN for {{% CRS %}} identifiers, for example `"urn:ogc:def:crs:epsg:7.1:4326"` -where `"7.1"` is the version of the EPSG database used. -URN may or may not be present in the set of identifiers returned by `crs.getIdentifiers()`. -In many cases (especially if the {{% CRS %}} was parsed from a Well Known Text), only simple identifiers like `"EPSG:4326"` are provided. -An easy way to build the full URN is to use the code below. -That example may scan the EPSG database for finding the information if it was not explicitly provided in the given {{% CRS %}}. - -{{< highlight java >}} -CoordinateReferenceSystem myCRS = ...; -String urn = IdentifiedObjects.lookupURN(myCRS); -{{< / highlight >}} - ### Is IdentifiedObjects.lookupEPSG(…) a reliable inverse of CRS.forCode(…)? {#lookupReliability} For {{% CRS %}} created from the EPSG geodetic dataset, usually yes. @@ -201,12 +109,6 @@ since it always compares the {{% CRS %}} with the database content. But it may fail if there is slight mismatch (for example rounding errors in projection parameters) between the supplied {{% CRS %}} and the {{% CRS %}} found in the database. -### How can I determine if two CRS are "functionally" equal? {#equalsIgnoreMetadata} - -Two Coordinate Reference Systems may not be considered equal if they are associated to different metadata -(name, identifiers, scope, domain of validity, remarks), even though they represent the same logical {{% CRS %}}. -In order to test if two {{% CRS %}} are functionally equivalent, use `Utilities.equalsIgnoreMetadata(myFirstCRS, mySecondCRS)`. - ### Are CRS objects safe for use as keys in HashMap? {#crsHashCode} Yes, every classes defined in the `org.apache.sis.referencing.crs`, `cs` and `datum` packages diff --git a/content/howto/_index.md b/content/howto/_index.md index ba3671f0..a7801e8e 100644 --- a/content/howto/_index.md +++ b/content/howto/_index.md @@ -3,8 +3,21 @@ title: How to --- Java code examples for performing some tasks with Apache {{% SIS %}}. +The examples are grouped in the following sections: -# Rasters +{{< toc >}} + + +# Referencing by coordinates {#referencing} + +* [Instantiate a Universal Transverse Mercator (UTM) projection](howto/instantiate_utm_projection.html) +* [Instantiate a Pseudo Mercator (a.k.a. Google) projection](faq.html#google) +* [Transform coordinates between two reference systems](howto/transform_coordinates.html) +* [Get the EPSG code or URN of an existing {{% CRS %}}](howto/lookup_crs_urn.html) +* [Determine if two {{% CRS %}} are functionally equal](howto/crs_equality.html) + + +# Grid coverages (rasters) {#raster} * [Get raster values at geographic coordinates](howto/raster_values_at_geographic_coordinates.html) * [Handle rasters bigger than memory](howto/rasters_bigger_than_memory.html) diff --git a/content/howto/crs_equality.md b/content/howto/crs_equality.md new file mode 100644 index 00000000..055493b9 --- /dev/null +++ b/content/howto/crs_equality.md @@ -0,0 +1,73 @@ +--- +title: Determine if two CRS are functionally equal +--- + +Two Coordinate Reference Systems may not be considered equal if they are associated to different metadata +(name, identifiers, scope, domain of validity, remarks), even though they represent the same logical {{% CRS %}}. +In order to test if two {{% CRS %}} are functionally equivalent, +`Utilities.equalsIgnoreMetadata(myFirstCRS, mySecondCRS)` can be used. + +In some cases, `equalsIgnoreMetadata(…)` may fail to see that two reference systems are equal. +It may happen for example when two map projections are defined with different parameters, +but are mathematically equivalent. +A more reliable but more costly way to check if two {{% CRS %}} are functionally equivalent +is to request the coordinate operation between them, and check if that operation is identity. + + +# Direct dependencies + +Maven coordinates | Module info +------------------------------------------- | ---------------------------- +`org.apache.sis.storage:sis-referencing` | `org.apache.sis.referencing` + + +# Code example + +{{< highlight java >}} +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.opengis.util.FactoryException; +import org.apache.sis.referencing.CRS; +import org.apache.sis.referencing.CommonCRS; +import org.apache.sis.util.Utilities; + +public class CrsEquality { + /** + * Demo entry point. + * + * @param args ignored. + * @throws FactoryException if an error occurred while creating the CRS + * or searching for a coordinate operation. + */ + public static void main(String[] args) throws FactoryException { + CoordinateReferenceSystem crs1 = CommonCRS.WGS84.geographic(); + CoordinateReferenceSystem crs2 = CRS.fromWKT( + """ + GeodeticCRS["WGS84 with a different name", + Datum["World Geodetic System 1984", + Ellipsoid["A different name", 6378137.0, 298.257223563]], + CS[ellipsoidal, 2], + Axis["Latitude (B)", north], + Axis["Longitude (L)", east], + Unit["degree", 0.017453292519943295]] + """); + + System.out.println("equals: " + + crs1.equals(crs2)); + + System.out.println("equalsIgnoreMetadata: " + + Utilities.equalsIgnoreMetadata(crs1, crs2)); + + System.out.println("Identity transform: " + + CRS.findOperation(crs2, crs2, null).getMathTransform().isIdentity()); + } +} +{{< / highlight >}} + + +# Output + +``` +equals: false +equalsIgnoreMetadata: true +Identity transform: true +``` diff --git a/content/howto/instantiate_utm_projection.md b/content/howto/instantiate_utm_projection.md new file mode 100644 index 00000000..145c6a0a --- /dev/null +++ b/content/howto/instantiate_utm_projection.md @@ -0,0 +1,91 @@ +--- +title: Instantiate a UTM projection +--- + +The Universal Transverse Mercator (UTM) projection divides the world in 60 zones. +If the UTM zone is unknown, an easy way to instantiate the projection +is to invoke the `universal(…)` method on one of the `CommonCRS` predefined constants. +That method receives in argument a geographic coordinate in (_latitude_, _longitude_) order and computes the UTM zone from it. +It takes in account the special cases of Norway and Svalbard. + +An alternative, more standard, way using geographic coordinates is to format an "AUTO" authority code. +The syntax is `"AUTO2:42001,1,<longitude>,<latitude>"`. +However this approach works only for the WGS84 datum. + +If the UTM zone is known, another way is to use the "EPSG" authority factory. +The EPSG code of some UTM projections can be determined as below, where _zone_ is a number from 1 to 60 inclusive (unless otherwise specified): + +* WGS 84 (northern hemisphere): 32600 + _zone_ +* WGS 84 (southern hemisphere): 32700 + _zone_ +* WGS 72 (northern hemisphere): 32200 + _zone_ +* WGS 72 (southern hemisphere): 32300 + _zone_ +* NAD 83 (northern hemisphere): 26900 + _zone_ (zone 1 to 23 only) +* NAD 27 (northern hemisphere): 26700 + _zone_ (zone 1 to 22 only) +* See the EPSG dataset for additional UTM definitions + (WGS 72BE, SIRGAS 2000, SIRGAS 1995, SAD 69, ETRS 89, _etc._). + +The code example below instantiates the same {{% CRS %}} using the three approaches. + + +# Direct dependencies + +Maven coordinates | Module info | Remarks +------------------------------------------- | ------------------------------------- | ----------------------------- +`org.apache.sis.storage:sis-referencing` | `org.apache.sis.referencing` | +`org.apache.sis.non-free:sis-embedded-data` | `org.apache.sis.referencing.database` | Optional. Non-Apache license. + +The [EPSG dependency](../epsg.html) is optional for examples using the `CommonCRS` enumeration +or the "AUTO" authority, but is required for examples using the "EPSG" authority. + + +# Code example + +Note that all geographic coordinates below express latitude *before* longitude, +except in "AUTO2" authority code. + +{{< highlight java >}} +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.opengis.util.FactoryException; +import org.apache.sis.referencing.CRS; +import org.apache.sis.referencing.CommonCRS; +import org.apache.sis.util.Utilities; + +public class InstantiateUTM { + /** + * Demo entry point. + * + * @param args ignored. + * @throws FactoryException if an error occurred while creating the Coordinate Reference System (CRS). + */ + public static void main(String[] args) throws FactoryException { + /* + * Get UTM projection for whatever zone is valid for 40°N 14°E. + */ + double latitude = 40; // Will determine the hemisphere. + double longitude = 14; // Will determine the UTM zone. + CoordinateReferenceSystem crsFromPoint = CommonCRS.WGS84.universal(latitude, longitude); + CoordinateReferenceSystem crsFromAUTO2 = CRS.forCode("AUTO2:42001,1," + longitude + "," + latitude); + /* + * Get the UTM projection for a specific zone. + */ + int zone = 33; // UTM zone 33. + int code = 32600 + zone; // For WGS84 northern hemisphere + CoordinateReferenceSystem crsFromCode = CRS.forCode("EPSG:" + code); + /* + * Compare the results. + */ + System.out.println("Are the CRS equivalent?"); + System.out.println("AUTO2: " + Utilities.equalsIgnoreMetadata(crsFromPoint, crsFromAUTO2)); + System.out.println("EPSG: " + Utilities.equalsIgnoreMetadata(crsFromPoint, crsFromCode)); + } +} +{{< / highlight >}} + + +# Output + +``` +Are the CRS equivalent? +AUTO2: true +EPSG: true +``` diff --git a/content/howto/lookup_crs_urn.md b/content/howto/lookup_crs_urn.md new file mode 100644 index 00000000..c2ebbf03 --- /dev/null +++ b/content/howto/lookup_crs_urn.md @@ -0,0 +1,95 @@ +--- +title: Get the EPSG code or URN of an existing CRS +--- + +The _identifier_ of a Coordinate Reference System (CRS) object can be obtained by the `getIdentifiers()` method, +which usually return a collection of zero or one element. +If the {{% CRS %}} has been created from a Well Known Text (WKT) parsing +and the {{% WKT %}} ends with an `AUTHORITY["EPSG", "xxxx"]` ({{% WKT %}} version 1) +or `ID["EPSG", xxxx]` ({{% WKT %}} version 2) element, +then the identifier (an EPSG numerical code in this example) is the _xxxx_ value in that element. +If the {{% CRS %}} has been created from the EPSG geodetic dataset (for example by a call to `CRS.forCode("EPSG:xxxx")`), +then the identifier is the _xxxx_ code given to that method. +If the {{% CRS %}} has been created in another way, then the collection returned by the `getIdentifiers()` method +may or may not be empty depending if the program that created the {{% CRS %}} took the responsibility of providing identifiers. + +If the collection of identifiers is empty, the most effective fix is to make sure that the {{% WKT %}} +contains an `AUTHORITY` or `ID` element (assuming that the {{% CRS %}} was parsed from a {{% WKT %}}). +If this is not possible, then the `org.apache.sis.referencing.IdentifiedObjects` class contains some convenience methods which may help. +In the following example, the call to `lookupEPSG(…)` will scan the EPSG database for a {{% CRS %}} equals +(ignoring metadata) to the given one. *Note that this scan is sensitive to axis order.* +Most geographic {{% CRS %}} in the EPSG database are declared with (_latitude_, _longitude_) axis order. +Consequently if the given {{% CRS %}} has (_longitude_, _latitude_) axis order, then the scan is likely to find no match. + + +# Direct dependencies + +Maven coordinates | Module info | Remarks +------------------------------------------- | ------------------------------------- | ----------------------------- +`org.apache.sis.storage:sis-referencing` | `org.apache.sis.referencing` | +`org.apache.sis.non-free:sis-embedded-data` | `org.apache.sis.referencing.database` | Optional. Non-Apache license. + +The [EPSG dependency](../epsg.html) is not needed if the {{% WKT %}} string declares an `AUTHORITY` element. +But it is required if the `AUTHORITY` element is absent and Apache {{% SIS %}} needs to scan the EPSG database +for finding its value. + + +# Code example + +{{< highlight java >}} +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.opengis.util.FactoryException; +import org.apache.sis.referencing.CRS; +import org.apache.sis.referencing.IdentifiedObjects; + +public class LookupAuthorityCode { + /** + * Demo entry point. + * + * @param args ignored. + * @throws FactoryException if an error occurred while creating the CRS or searching in EPSG database. + */ + public static void main(String[] args) throws FactoryException { + CoordinateReferenceSystem crs = CRS.fromWKT( + """ + PROJCRS["NTF (Paris) / zone to be discovered by the demo", + BASEGEODCRS["NTF (Paris)", + DATUM["Nouvelle Triangulation Francaise", + ELLIPSOID["Clarke 1880 (IGN)", 6378249.2, 293.4660212936269]], + PRIMEM["Paris", 2.5969213], + UNIT["grade", 0.015707963267948967]], + CONVERSION["Lambert zone II", + METHOD["Lambert Conic Conformal (1SP)"], + PARAMETER["Latitude of natural origin", 52.0], + PARAMETER["Longitude of natural origin", 0.0], + PARAMETER["Scale factor at natural origin", 0.99987742], + PARAMETER["False easting", 600000.0], + PARAMETER["False northing", 2200000.0]], + CS[Cartesian, 2], + AXIS["Easting (E)", east], + AXIS["Northing (N)", north], + LENGTHUNIT["metre", 1], + REMARK["EPSG:27572 identifier intentionally omitted."]] + """); + + System.out.println("Identifier declared in the CRS: " + + IdentifiedObjects.getIdentifier(crs, null)); + + System.out.println("Searching in EPSG database: " + + IdentifiedObjects.lookupEPSG(crs)); + + System.out.println("Same, but more generic: " + + IdentifiedObjects.lookupURN(crs, null)); + } +} +{{< / highlight >}} + + +# Output + +``` +Identifier declared in the CRS: null +Searching in EPSG database: 27572 +Same, but more generic: urn:ogc:def:crs:EPSG:9.9.1:27572 + +``` diff --git a/content/howto/raster_values_at_geographic_coordinates.md b/content/howto/raster_values_at_geographic_coordinates.md index 334f075d..5dd8ecf1 100644 --- a/content/howto/raster_values_at_geographic_coordinates.md +++ b/content/howto/raster_values_at_geographic_coordinates.md @@ -30,13 +30,13 @@ Maven coordinates | Module info | Remarks 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. +see the [rasters bigger than memory](rasters_bigger_than_memory.html) code example. -# Code snippet +# Code example The file name, resource name and geographic coordinates -in following snippet need to be updated for yours data. +in following code need to be updated for yours data. {{< highlight java >}} import java.io.File; diff --git a/content/howto/rasters_bigger_than_memory.md b/content/howto/rasters_bigger_than_memory.md index c6d89544..55bbb600 100644 --- a/content/howto/rasters_bigger_than_memory.md +++ b/content/howto/rasters_bigger_than_memory.md @@ -13,7 +13,7 @@ It integrates well with operations provided by Apache {{% SIS %}} such as 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. +[values at geographic coordinates](raster_values_at_geographic_coordinates.html) code example. # Direct dependencies @@ -27,9 +27,9 @@ 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 +# Code example -The file name in following snippet need to be updated for yours data. +The file name in following code need to be updated for yours data. {{< highlight java >}} import java.io.File; diff --git a/content/howto/resample_and_save_raster.md b/content/howto/resample_and_save_raster.md index 039299ff..8ad62710 100644 --- a/content/howto/resample_and_save_raster.md +++ b/content/howto/resample_and_save_raster.md @@ -20,13 +20,16 @@ But it would also be possible to specify a CRS without EPSG code, for example using Well Known Text (WKT) format. -# Code snippet +# Code example -The file name in following snippet need to be updated for yours data. +The file name in following code need to be updated for yours data. {{< highlight java >}} +import java.io.File; +import java.io.IOException; import java.nio.file.Paths; import java.util.Collection; +import javax.imageio.ImageIO; import java.awt.image.ImagingOpException; import org.apache.sis.storage.Resource; import org.apache.sis.storage.Aggregate; @@ -51,7 +54,7 @@ public class ResampleAndSaveRaster { * @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 { + public static void main(String[] args) throws DataStoreException, FactoryException, TransformException, IOException { try (DataStore store = DataStores.open(Paths.get("Airport.tiff"))) { /* * This data store is an aggregate because a GeoTIFF file may contain many images. @@ -77,10 +80,12 @@ public class ResampleAndSaveRaster { 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. + * TODO: Apache SIS is missing a `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. + * For now we use Java I/O API. */ + ImageIO.write(data.render(null), "png", new File("test.png")); } } } diff --git a/content/howto/transform_coordinates.md b/content/howto/transform_coordinates.md new file mode 100644 index 00000000..455a235c --- /dev/null +++ b/content/howto/transform_coordinates.md @@ -0,0 +1,86 @@ +--- +title: Transform coordinates +--- + +The following Java code projects geographic coordinates from the _World Geodetic System 1984_ (WGS84) to _WGS 84 / UTM zone 33N_. +In order to make the example a little bit simpler, this code uses predefined constants given by the `CommonCRS` convenience class. +But more advanced applications may use [EPSG codes](../epsg.html) or definitions in Well-Known Text (WKT) instead. + +**Note:** if the result of a coordinate transformation seems wrong, see the [FAQ](../faq.html) page. +Unexpected results are often caused by wrong axis order. + + +# Direct dependencies + +Maven coordinates | Module info | Remarks +------------------------------------------- | ------------------------------------- | ----------------------------- +`org.apache.sis.storage:sis-referencing` | `org.apache.sis.referencing` | +`org.apache.sis.non-free:sis-embedded-data` | `org.apache.sis.referencing.database` | Optional. Non-Apache license. + +The [EPSG dependency](../epsg.html) is optional for this example. +But if present, the Coordinate Reference Systems will have more metadata. +Consequently, coordinate transformation results between some pairs of reference systems +may be different depending on whether the EPSG dataset is present or not. +In general, results are more accurate and/or more reliable in presence of EPSG dataset. + + +# Code example + +Note that all geographic coordinates below express latitude *before* longitude. + +{{< highlight java >}} +import org.opengis.geometry.DirectPosition; +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.opengis.referencing.operation.CoordinateOperation; +import org.opengis.referencing.operation.TransformException; +import org.opengis.util.FactoryException; +import org.apache.sis.referencing.CRS; +import org.apache.sis.referencing.CommonCRS; +import org.apache.sis.geometry.DirectPosition2D; + +public class TransformCoordinates { + /** + * Demo entry point. + * + * @param args ignored. + * @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. + */ + public static void main(String[] args) throws FactoryException, TransformException { + CoordinateReferenceSystem sourceCRS = CommonCRS.WGS84.geographic(); + CoordinateReferenceSystem targetCRS = CommonCRS.WGS84.universal(40, 14); // UTM zone for 40°N 14°E. + CoordinateOperation operation = CRS.findOperation(sourceCRS, targetCRS, null); + /* + * The above lines are costly and should be performed only once before to project many points. + * In this example, the operation that we got is valid for coordinates in geographic area from + * 12°E to 18°E (UTM zone 33) and 0°N to 84°N. + */ + System.out.println("Domain of validity:"); + System.out.println(CRS.getGeographicBoundingBox(operation)); + + DirectPosition ptSrc = new DirectPosition2D(40, 14); // 40°N 14°E + DirectPosition ptDst = operation.getMathTransform().transform(ptSrc, null); + + System.out.println("Source: " + ptSrc); + System.out.println("Target: " + ptDst); + } +} +{{< / highlight >}} + + +# Output + +Note: for some pairs of Coordinate Reference Systems, +the output may vary depending on whether the [EPSG geodetic dataset](../epsg.html) is present or not. + +``` +Domain of validity: +Geographic bounding box + ├─West bound longitude…… 12°E + ├─East bound longitude…… 18°E + ├─South bound latitude…… 0°N + └─North bound latitude…… 84°N + +Source: POINT(40 14) +Target: POINT(414639.5381572213 4428236.064633072) +```