diff --git a/CHANGELOG.md b/CHANGELOG.md index 78d5f1a0..f35e53f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Breaking changes (migration guide) + +- `ProjectionTransformerFactory` has a new required method `String getWKT(int srid, boolean longitudeFirst)`, the WKT 1 definition of a CRS the factory supports, optionally with x/y axis order forced. Custom implementations must add it. `hakunapi-gpkg` uses it for `gpkg_spatial_ref_sys` and no longer depends on GeoTools (`gt-epsg-hsql`) itself; the GeoPackage output now needs a projection factory that provides WKT, as `hakunapi-proj-gt` does. `JHeProjectionTransformerFactory` (community) throws `UnsupportedOperationException` for now. + ### Internationalization / Localization - **Language negotiation for descriptive elements.** The landing page, @@ -84,6 +88,10 @@ - `servers` is now trimmed like the other list keys: `servers=dev, prod` works instead of failing startup with a `NullPointerException`. - PostGIS source: the keys `collections..id.alias`, `geometry.alias` and `properties.

.alias` are removed. They were a not-working and unfinished idea (`properties.

.alias` made startup fail with a `NullPointerException`); they are now ignored. +### Library updates + +- `hakunapi-proj-gt` excludes `gt-epsg-hsql`'s transitive `net.opengis.ows`, `org.w3.xlink`, the three `org.eclipse.emf` jars, `imagen-core` and `commons-lang3` (~4 MB). GeoTools references them only from ISO citation metadata, raster parameters and URN/PROJ formatting, none of which hakunapi uses; transformations and WKT are unchanged. + ## 2.0.0 For a full list of changes see: https://github.com/nlsfi/hakunapi/milestone/17 diff --git a/docs/overview/modules.md b/docs/overview/modules.md index b51d8d9b..449e9f3a 100644 --- a/docs/overview/modules.md +++ b/docs/overview/modules.md @@ -72,7 +72,7 @@ The table below lists all direct third-party dependencies declared in the Hakuna | Library | Version | Purpose | Notes | | --- | --- | --- | --- | | JTS Topology Suite | 1.20.0 | Geometry model, spatial predicates | | -| GeoTools | 35.1 | proj-gt: `gt-epsg-hsql` provides EPSG CRS database (HSQL-backed) for CRS definitions and reprojection | **To consider:** hakunapi-proj-proj (PROJ) [Issue #143](https://github.com/nlsfi/hakunapi/issues/143) to replace hakunapi-proj-gt for CRS definitions and reprojection? | +| GeoTools | 35.1 | proj-gt: `gt-epsg-hsql` provides EPSG CRS database (HSQL-backed) for CRS definitions and reprojection. Transitive OWS/xlink/EMF, ImageN and commons-lang3 are excluded: only GeoTools code paths hakunapi does not use reference them | **To consider:** hakunapi-proj-proj (PROJ) [Issue #143](https://github.com/nlsfi/hakunapi/issues/143) to replace hakunapi-proj-gt for CRS definitions and reprojection? | #### Database connectivity @@ -295,7 +295,7 @@ Key differences between PostGIS and GeoPackage support in Hakunapi: [`hakunapi-tiles-source-pmtiles`](../../src-community/hakunapi-tiles-source-pmtiles/README.md) *(community module)* is a `MapTileSource` and a `VectorTileSource` serving the tiles of a PMTiles v3 archive, read in place from a local file or over HTTP range requests. It is found with `ServiceLoader`, so it is enabled by being on the classpath, and is not bundled in the reference webapp. It depends on `hakunapi-tiles-core` and `slf4j-api`; it adds no new third-party dependency. -[`hakunapi-tiles-generator`](../../src-community/hakunapi-tiles-generator/README.md) *(community module)* is a command-line seed tool, not a server module: `TilesGenerator` writes a vector tile pyramid into a GeoPackage from the feature sources of a service configuration, and `PMTilesConvert` turns such a pyramid into a PMTiles v3 archive. Run `TilesGenerator` with its jar (`java -cp fi.nls.hakunapi.tiles.generator.TilesGenerator `), and `PMTilesConvert` the same way with its main class and ` `. It depends at compile time on `hakunapi-tiles-core`, `hakunapi-tiles-source-vectortile`, `hakunapi-gpkg`, `hakunapi-cql2` and `hakunapi-tiles-source-pmtiles`, and at runtime on `hakunapi-crs-properties`, which is loaded with `ServiceLoader` and not imported. Its only test dependency is `junit`. It is not bundled in the reference webapp. +[`hakunapi-tiles-generator`](../../src-community/hakunapi-tiles-generator/README.md) *(community module)* is a command-line seed tool, not a server module: `TilesGenerator` writes a vector tile pyramid into a GeoPackage from the feature sources of a service configuration, and `PMTilesConvert` turns such a pyramid into a PMTiles v3 archive. Run `TilesGenerator` with its jar (`java -cp fi.nls.hakunapi.tiles.generator.TilesGenerator `), and `PMTilesConvert` the same way with its main class and `
`. It depends at compile time on `hakunapi-tiles-core`, `hakunapi-tiles-source-vectortile`, `hakunapi-gpkg`, `hakunapi-cql2` and `hakunapi-tiles-source-pmtiles`, and at runtime on `hakunapi-crs-properties`, which is loaded with `ServiceLoader` and not imported, and `hakunapi-proj-gt`, the default projection factory, loaded by class name. Its only test dependency is `junit`. It is not bundled in the reference webapp. ## Output data formats (stable) @@ -323,7 +323,7 @@ The map on the items and item pages is a demo feature. A background tile layer i ### GeoPackage -The [GeoPackage (GPKG)](https://www.geopackage.org/) output format (the media type `application/geopackage+vnd.sqlite3`) is supported by the `hakunapi-gpgk` module. When needed it must be enabled using a configuration like `formats=geojson,gpgk`. The implementation supports outputting same feature, feature collection, property and geometry objects (Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon and GeometryCollection) as GeoJSON writer too. +The [GeoPackage (GPKG)](https://www.geopackage.org/) output format (the media type `application/geopackage+vnd.sqlite3`) is supported by the `hakunapi-gpgk` module. When needed it must be enabled using a configuration like `formats=geojson,gpgk`. The implementation supports outputting same feature, feature collection, property and geometry objects (Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon and GeometryCollection) as GeoJSON writer too. The CRS definition (WKT) written to `gpkg_spatial_ref_sys` comes from the collection's projection factory (`ProjectionTransformerFactory.getWKT`, with x/y axis order like the geometries), so the module itself has no GeoTools dependency. Currently [OGC API Features](https://ogcapi.ogc.org/features/) does not specify anything related to GPGK. Some feature service metadata (like next links) cannot be written in content payload like in the case of the default GeoJSON output. Such metadata should be provided as HTTP headers (an optional capability specified by OGC API Features), but support in Hakunapi is still an [upcoming feature](https://github.com/nlsfi/hakunapi/issues/91). diff --git a/src-community/hakunapi-proj-jhe/src/main/java/fi/nls/hakunapi/proj/jhe/JHeProjectionTransformerFactory.java b/src-community/hakunapi-proj-jhe/src/main/java/fi/nls/hakunapi/proj/jhe/JHeProjectionTransformerFactory.java index bc1e8268..fc34a11d 100644 --- a/src-community/hakunapi-proj-jhe/src/main/java/fi/nls/hakunapi/proj/jhe/JHeProjectionTransformerFactory.java +++ b/src-community/hakunapi-proj-jhe/src/main/java/fi/nls/hakunapi/proj/jhe/JHeProjectionTransformerFactory.java @@ -31,6 +31,11 @@ public ProjectionTransformer fromCRS84(int sridTo) throws Exception { return getTransformer(4258, sridTo); } + @Override + public String getWKT(int srid, boolean longitudeFirst) throws Exception { + throw new UnsupportedOperationException("WKT definitions are not supported by JHe"); + } + private String getCacheKey(int sridFrom, int sridTo) { return sridFrom + "_" + sridTo; } diff --git a/src-community/hakunapi-tiles-generator/README.md b/src-community/hakunapi-tiles-generator/README.md index f5d98f93..ea327b36 100644 --- a/src-community/hakunapi-tiles-generator/README.md +++ b/src-community/hakunapi-tiles-generator/README.md @@ -207,7 +207,8 @@ the table, converted to WGS84 with the pyramid's own SRID; the centre is the middle of that extent. Nothing is assumed about where the data is. Converting a CRS other than EPSG:4326 needs a projection factory on the classpath (`-Dhakunapi.proj=`, default `fi.nls.hakunapi.proj.gt.GeoToolsProjectionTransformerFactory`, -as for a service configuration); without one, pass `--bbox`. +as for a service configuration); without one, pass `--bbox`. `hakunapi-proj-gt` +is bundled. The archive keeps the pyramid's own tile addressing. Every zoom must be a `2^z` by `2^z` matrix, because a PMTiles tile id is a Hilbert index over a diff --git a/src-community/hakunapi-tiles-generator/pom.xml b/src-community/hakunapi-tiles-generator/pom.xml index a27d7082..33d87e9d 100644 --- a/src-community/hakunapi-tiles-generator/pom.xml +++ b/src-community/hakunapi-tiles-generator/pom.xml @@ -23,6 +23,12 @@ fi.nls.hakunapi hakunapi-gpkg + + + fi.nls.hakunapi + hakunapi-proj-gt + runtime + fi.nls.hakunapi diff --git a/src-community/hakunapi-tiles-generator/src/main/java/fi/nls/hakunapi/tiles/generator/TilesGenerator.java b/src-community/hakunapi-tiles-generator/src/main/java/fi/nls/hakunapi/tiles/generator/TilesGenerator.java index 161a4f7d..67a922a1 100644 --- a/src-community/hakunapi-tiles-generator/src/main/java/fi/nls/hakunapi/tiles/generator/TilesGenerator.java +++ b/src-community/hakunapi-tiles-generator/src/main/java/fi/nls/hakunapi/tiles/generator/TilesGenerator.java @@ -16,6 +16,7 @@ import fi.nls.hakunapi.core.FeatureType; import fi.nls.hakunapi.core.FilterParser; import fi.nls.hakunapi.core.config.HakunaConfigParser; +import fi.nls.hakunapi.core.projection.ProjectionTransformerFactory; import fi.nls.hakunapi.cql2.text.CQL2Text; import fi.nls.hakunapi.gpkg.GPKG; import fi.nls.hakunapi.gpkg.GPKGSpatialRefSystems; @@ -94,7 +95,7 @@ private static int generate(Args parsed, GeneratorControl control, TileSources s GPKG.init(c); } GPKG.initTiles(c); - GPKG.insertSpatialRefSys(c, GPKGSpatialRefSystems.get(tms.getSrid())); + GPKG.insertSpatialRefSys(c, GPKGSpatialRefSystems.get(tms.getSrid(), projectionFactory(collections))); List existing = PyramidTables.existingTables(c, tables); if (!existing.isEmpty()) { @@ -133,6 +134,11 @@ private static VectorTileGenerator resolveGenerator(String type) { return generator; } + // The CRS definition comes from the same factory the collections are transformed with + private static ProjectionTransformerFactory projectionFactory(Map> collections) { + return collections.values().iterator().next().get(0).getProjectionTransformerFactory(); + } + private static void validateZooms(GeneratorControl control, TileMatrixSet tms, int minZoom, int maxZoom) { if (minZoom > maxZoom) { throw new IllegalArgumentException("--min-zoom " + minZoom + " is above --max-zoom " + maxZoom); diff --git a/src-community/hakunapi-tiles-generator/src/test/java/fi/nls/hakunapi/tiles/generator/PyramidBoundsTest.java b/src-community/hakunapi-tiles-generator/src/test/java/fi/nls/hakunapi/tiles/generator/PyramidBoundsTest.java index 3350acad..624652fe 100644 --- a/src-community/hakunapi-tiles-generator/src/test/java/fi/nls/hakunapi/tiles/generator/PyramidBoundsTest.java +++ b/src-community/hakunapi-tiles-generator/src/test/java/fi/nls/hakunapi/tiles/generator/PyramidBoundsTest.java @@ -17,6 +17,7 @@ import fi.nls.hakunapi.gpkg.GPKG; import fi.nls.hakunapi.gpkg.GPKGSpatialRefSystems; +import fi.nls.hakunapi.proj.gt.GeoToolsProjectionTransformerFactory; import fi.nls.hakunapi.tiles.TileMatrix; import fi.nls.hakunapi.tiles.TileMatrixSet; @@ -35,7 +36,7 @@ private Connection pyramid(int srid, String... tiles) throws Exception { Connection c = DriverManager.getConnection("jdbc:sqlite:" + path); GPKG.init(c); GPKG.initTiles(c); - GPKG.insertSpatialRefSys(c, GPKGSpatialRefSystems.get(srid)); + GPKG.insertSpatialRefSys(c, GPKGSpatialRefSystems.get(srid, new GeoToolsProjectionTransformerFactory())); PyramidTables.createTables(c, List.of("t"), new TileMatrixSet("T", "T", "urn:x", srid, matrices), 0, 2); try (Statement st = c.createStatement()) { for (String tile : tiles) { diff --git a/src-community/hakunapi-tiles-generator/src/test/java/fi/nls/hakunapi/tiles/generator/PyramidGeneratorTest.java b/src-community/hakunapi-tiles-generator/src/test/java/fi/nls/hakunapi/tiles/generator/PyramidGeneratorTest.java index 6b8773ef..f6ab335e 100644 --- a/src-community/hakunapi-tiles-generator/src/test/java/fi/nls/hakunapi/tiles/generator/PyramidGeneratorTest.java +++ b/src-community/hakunapi-tiles-generator/src/test/java/fi/nls/hakunapi/tiles/generator/PyramidGeneratorTest.java @@ -31,6 +31,7 @@ import fi.nls.hakunapi.core.config.HakunaConfigParser; import fi.nls.hakunapi.gpkg.GPKG; import fi.nls.hakunapi.gpkg.GPKGSpatialRefSystems; +import fi.nls.hakunapi.proj.gt.GeoToolsProjectionTransformerFactory; import fi.nls.hakunapi.tiles.TileBody; import fi.nls.hakunapi.tiles.TileMatrix; import fi.nls.hakunapi.tiles.TileMatrixSet; @@ -93,7 +94,7 @@ private Path generate(StubCollection[] stubs, GeneratorControl control, TileSour try (Connection c = open(out)) { GPKG.init(c); GPKG.initTiles(c); - GPKG.insertSpatialRefSys(c, GPKGSpatialRefSystems.get(SRID)); + GPKG.insertSpatialRefSys(c, GPKGSpatialRefSystems.get(SRID, new GeoToolsProjectionTransformerFactory())); PyramidTables.createTables(c, tables, tms, minZoom, maxZoom); PyramidGenerator pyramid = new PyramidGenerator(control, sources, tms, generator, @@ -222,7 +223,7 @@ public Optional generate(TileContext ctx, List collection try (Connection c = open(out)) { GPKG.init(c); GPKG.initTiles(c); - GPKG.insertSpatialRefSys(c, GPKGSpatialRefSystems.get(SRID)); + GPKG.insertSpatialRefSys(c, GPKGSpatialRefSystems.get(SRID, new GeoToolsProjectionTransformerFactory())); PyramidTables.createTables(c, tables, tms, 0, 3); PyramidGenerator pyramid = new PyramidGenerator(control, sources, tms, failing, VectorTileGeneratorSource.DEFAULT_MEDIA_TYPE, @@ -245,7 +246,7 @@ public void tileMetadataIsCompleteAndInitTilesIsIdempotent() throws Exception { GPKG.init(c); GPKG.initTiles(c); GPKG.initTiles(c); - GPKG.insertSpatialRefSys(c, GPKGSpatialRefSystems.get(SRID)); + GPKG.insertSpatialRefSys(c, GPKGSpatialRefSystems.get(SRID, new GeoToolsProjectionTransformerFactory())); PyramidTables.createTables(c, List.of("tieviiva"), scheme(), 1, 2); assertTrue(PyramidTables.existingTables(c, List.of("tieviiva", "x")).equals(List.of("tieviiva"))); try (Statement st = c.createStatement()) { diff --git a/src/hakunapi-core/src/main/java/fi/nls/hakunapi/core/projection/ProjectionTransformerFactory.java b/src/hakunapi-core/src/main/java/fi/nls/hakunapi/core/projection/ProjectionTransformerFactory.java index 69f89da8..ce6f220b 100644 --- a/src/hakunapi-core/src/main/java/fi/nls/hakunapi/core/projection/ProjectionTransformerFactory.java +++ b/src/hakunapi-core/src/main/java/fi/nls/hakunapi/core/projection/ProjectionTransformerFactory.java @@ -5,5 +5,10 @@ public interface ProjectionTransformerFactory { public ProjectionTransformer getTransformer(int fromSRID, int toSRID) throws Exception; public ProjectionTransformer toCRS84(int fromSRID) throws Exception; public ProjectionTransformer fromCRS84(int toSRID) throws Exception; + /** + * @param longitudeFirst force x/y (easting/longitude first) axis order instead of the authority's + * @return WKT 1 definition of the CRS, required for every srid this factory can transform + */ + public String getWKT(int srid, boolean longitudeFirst) throws Exception; } diff --git a/src/hakunapi-core/src/test/java/fi/nls/hakunapi/core/param/BboxAntimeridianTest.java b/src/hakunapi-core/src/test/java/fi/nls/hakunapi/core/param/BboxAntimeridianTest.java index e2be1e76..23bd8a53 100644 --- a/src/hakunapi-core/src/test/java/fi/nls/hakunapi/core/param/BboxAntimeridianTest.java +++ b/src/hakunapi-core/src/test/java/fi/nls/hakunapi/core/param/BboxAntimeridianTest.java @@ -73,6 +73,11 @@ public ProjectionTransformer toCRS84(int fromSRID) { public ProjectionTransformer fromCRS84(int toSRID) { return NOPProjectionTransformer.INSTANCE; } + + @Override + public String getWKT(int srid, boolean longitudeFirst) { + throw new UnsupportedOperationException(); + } }); service = new FeatureServiceConfig() { diff --git a/src/hakunapi-core/src/test/java/fi/nls/hakunapi/core/param/BboxCrsParamTest.java b/src/hakunapi-core/src/test/java/fi/nls/hakunapi/core/param/BboxCrsParamTest.java index e85b223d..89b78d29 100644 --- a/src/hakunapi-core/src/test/java/fi/nls/hakunapi/core/param/BboxCrsParamTest.java +++ b/src/hakunapi-core/src/test/java/fi/nls/hakunapi/core/param/BboxCrsParamTest.java @@ -60,6 +60,11 @@ public ProjectionTransformer toCRS84(int fromSRID) { public ProjectionTransformer fromCRS84(int toSRID) { return NOPProjectionTransformer.INSTANCE; } + + @Override + public String getWKT(int srid, boolean longitudeFirst) { + throw new UnsupportedOperationException(); + } }); service = new FeatureServiceConfig() { diff --git a/src/hakunapi-core/src/test/java/fi/nls/hakunapi/core/property/simple/HakunaPropertyGeometryTest.java b/src/hakunapi-core/src/test/java/fi/nls/hakunapi/core/property/simple/HakunaPropertyGeometryTest.java index 73650aba..8992faa7 100644 --- a/src/hakunapi-core/src/test/java/fi/nls/hakunapi/core/property/simple/HakunaPropertyGeometryTest.java +++ b/src/hakunapi-core/src/test/java/fi/nls/hakunapi/core/property/simple/HakunaPropertyGeometryTest.java @@ -114,6 +114,11 @@ public ProjectionTransformer toCRS84(int fromSRID) { public ProjectionTransformer fromCRS84(int toSRID) { throw new UnsupportedOperationException(); } + + @Override + public String getWKT(int srid, boolean longitudeFirst) { + throw new UnsupportedOperationException(); + } }); HakunaPropertyGeometry prop = new HakunaPropertyGeometry("geometry", "table", "geom", false, null, new int[0], 3067, 2, HakunaPropertyWriters.HIDDEN); diff --git a/src/hakunapi-gpkg/pom.xml b/src/hakunapi-gpkg/pom.xml index 9d36294b..0f307588 100644 --- a/src/hakunapi-gpkg/pom.xml +++ b/src/hakunapi-gpkg/pom.xml @@ -30,11 +30,6 @@ sqlite-jdbc ${sqlite-jdbc.version} - - org.geotools - gt-epsg-hsql - ${geotools.version} - junit junit diff --git a/src/hakunapi-gpkg/src/main/java/fi/nls/hakunapi/gpkg/GPKGFeatureCollectionWriter.java b/src/hakunapi-gpkg/src/main/java/fi/nls/hakunapi/gpkg/GPKGFeatureCollectionWriter.java index 86e9d325..a0af9c3a 100644 --- a/src/hakunapi-gpkg/src/main/java/fi/nls/hakunapi/gpkg/GPKGFeatureCollectionWriter.java +++ b/src/hakunapi-gpkg/src/main/java/fi/nls/hakunapi/gpkg/GPKGFeatureCollectionWriter.java @@ -111,7 +111,7 @@ public void endFeatureCollection() throws Exception { } insert.close(); GPKGGeometryColumn geometryColumn = createGeometryColumn(); - GPKGSpatialRefSys srs = GPKGSpatialRefSystems.get(srid.getSrid()); + GPKGSpatialRefSys srs = GPKGSpatialRefSystems.get(srid.getSrid(), ft.getProjectionTransformerFactory()); GPKG.insertSpatialRefSys(c, srs); GPKGFeaturesTable tableEntry = new GPKGFeaturesTable(tableName, ft.getTitle(), ft.getDescription(), envelope, srs.getSrsId()); GPKG.insertFeaturesTableEntry(c, tableEntry); diff --git a/src/hakunapi-gpkg/src/main/java/fi/nls/hakunapi/gpkg/GPKGSpatialRefSystems.java b/src/hakunapi-gpkg/src/main/java/fi/nls/hakunapi/gpkg/GPKGSpatialRefSystems.java index d777c59c..7b60ea71 100644 --- a/src/hakunapi-gpkg/src/main/java/fi/nls/hakunapi/gpkg/GPKGSpatialRefSystems.java +++ b/src/hakunapi-gpkg/src/main/java/fi/nls/hakunapi/gpkg/GPKGSpatialRefSystems.java @@ -1,11 +1,9 @@ package fi.nls.hakunapi.gpkg; -import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; -import org.geotools.api.referencing.crs.CoordinateReferenceSystem; -import org.geotools.referencing.CRS; - +import fi.nls.hakunapi.core.projection.ProjectionTransformerFactory; import fi.nls.hakunapi.core.schemas.Crs; public class GPKGSpatialRefSystems { @@ -16,7 +14,7 @@ private GPKGSpatialRefSystems() {} public static final GPKGSpatialRefSys UNDEFINED_CARTESIAN = new GPKGSpatialRefSys("Undefined Cartesian", -1, "NONE", -1, "undefined", "undefined"); public static final GPKGSpatialRefSys UNDEFINED_GEOGRAPHIC = new GPKGSpatialRefSys("Undefined Geographic", 0, "NONE", 0, "undefined", "undefined"); - private static final Map BY_SRID = new HashMap<>(); + private static final Map BY_SRID = new ConcurrentHashMap<>(); static { register(WGS84); register(UNDEFINED_CARTESIAN); @@ -27,21 +25,21 @@ public static void register(GPKGSpatialRefSys sys) { BY_SRID.put(sys.getSrsId(), sys); } - public static GPKGSpatialRefSys get(int srid) { + public static GPKGSpatialRefSys get(int srid, ProjectionTransformerFactory proj) { if (srid == Crs.CRS84_SRID) { return WGS84; } - return BY_SRID.computeIfAbsent(srid, GPKGSpatialRefSystems::epsg); + return BY_SRID.computeIfAbsent(srid, __ -> epsg(srid, proj)); } - private static GPKGSpatialRefSys epsg(int srid) { + private static GPKGSpatialRefSys epsg(int srid, ProjectionTransformerFactory proj) { try { String srsName = "EPSG:" + srid; - CoordinateReferenceSystem crs = CRS.decode(srsName, true); - String definition = crs.toWKT(); + // Geometries are always x/y in a GeoPackage, keep the definition consistent with them + String definition = proj.getWKT(srid, true); return new GPKGSpatialRefSys(srsName, srid, "EPSG", srid, definition, srsName); } catch (Exception e) { - throw new RuntimeException("Could not decode CRS for srid: " + srid); + throw new RuntimeException("Could not decode CRS for srid: " + srid, e); } } diff --git a/src/hakunapi-proj-gt/pom.xml b/src/hakunapi-proj-gt/pom.xml index fe78f6f9..6805f617 100644 --- a/src/hakunapi-proj-gt/pom.xml +++ b/src/hakunapi-proj-gt/pom.xml @@ -25,6 +25,37 @@ org.geotools gt-epsg-hsql ${geotools.version} + + + + org.geotools.ogc + net.opengis.ows + + + org.geotools.ogc + org.w3.xlink + + + org.eclipse.emf + org.eclipse.emf.common + + + org.eclipse.emf + org.eclipse.emf.ecore + + + org.eclipse.emf + org.eclipse.emf.ecore.xmi + + + org.eclipse.imagen + imagen-core + + + org.apache.commons + commons-lang3 + + junit diff --git a/src/hakunapi-proj-gt/src/main/java/fi/nls/hakunapi/proj/gt/GeoToolsProjectionTransformerFactory.java b/src/hakunapi-proj-gt/src/main/java/fi/nls/hakunapi/proj/gt/GeoToolsProjectionTransformerFactory.java index 7a4b9593..5a68ba56 100644 --- a/src/hakunapi-proj-gt/src/main/java/fi/nls/hakunapi/proj/gt/GeoToolsProjectionTransformerFactory.java +++ b/src/hakunapi-proj-gt/src/main/java/fi/nls/hakunapi/proj/gt/GeoToolsProjectionTransformerFactory.java @@ -73,6 +73,11 @@ public ProjectionTransformer fromCRS84(int sridTo) throws Exception { return getProjectionTransformer(Crs.CRS84_SRID, CRS84, sridTo, getHorizontalCRS(sridTo)); } + @Override + public String getWKT(int srid, boolean longitudeFirst) throws Exception { + return CRS.decode("EPSG:" + srid, longitudeFirst).toWKT(); + } + private static CoordinateReferenceSystem getHorizontalCRS(int srid) throws Exception { CoordinateReferenceSystem crs = CRS.decode("EPSG:" + srid, true); if (crs instanceof CompoundCRS) { diff --git a/src/hakunapi-proj-gt/src/test/java/fi/nls/hakunapi/proj/gt/GeoToolsProjectionTransformerTest.java b/src/hakunapi-proj-gt/src/test/java/fi/nls/hakunapi/proj/gt/GeoToolsProjectionTransformerTest.java index 84e5455b..1290bf45 100644 --- a/src/hakunapi-proj-gt/src/test/java/fi/nls/hakunapi/proj/gt/GeoToolsProjectionTransformerTest.java +++ b/src/hakunapi-proj-gt/src/test/java/fi/nls/hakunapi/proj/gt/GeoToolsProjectionTransformerTest.java @@ -1,6 +1,7 @@ package fi.nls.hakunapi.proj.gt; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import org.junit.Ignore; import org.junit.Test; @@ -20,6 +21,23 @@ public void testCRS84to3067() throws Exception { assertEquals(6651411.193370228, coords[1], 1e-8); } + @Test + public void testWKT3067() throws Exception { + ProjectionTransformerFactory fact = new GeoToolsProjectionTransformerFactory(); + String wkt = fact.getWKT(3067, true); + assertTrue(wkt, wkt.startsWith("PROJCS[\"EUREF-FIN / TM35FIN(E,N)\"")); + assertTrue(wkt, wkt.endsWith("AUTHORITY[\"EPSG\",\"3067\"]]")); + } + + @Test + public void testWKTAxisOrder4258() throws Exception { + ProjectionTransformerFactory fact = new GeoToolsProjectionTransformerFactory(); + String xy = fact.getWKT(4258, true); + String authority = fact.getWKT(4258, false); + assertTrue(xy, xy.indexOf("EAST]") < xy.indexOf("NORTH]")); + assertTrue(authority, authority.indexOf("NORTH]") < authority.indexOf("EAST]")); + } + @Test @Ignore("Issue with Java asserts with 4258 (lon,lat) -> 10690 (lon,lat) step being NO-OP") public void test4258to3067() throws Exception {