From e9978679e86dcd297270432e4ed953b782f1e7c6 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Thu, 26 Oct 2023 08:44:33 +0200 Subject: [PATCH] Fix lat/lon vs. lon/lat issues --- js/src/geo/BboxVectorSource.js | 4 ++-- js/src/geo/OpenLayersMapPart.js | 4 ++-- js/src/geo/OpenLayersUtils.js | 21 +++++++++++++++++-- .../org/argeo/app/api/geo/FeatureAdapter.java | 18 +++++++--------- .../src/org/argeo/app/geo/GeoJson.java | 10 +++++---- .../src/org/argeo/app/geo/GpxUtils.java | 4 ++-- .../argeo/app/geo/http/WfsHttpHandler.java | 9 ++------ 7 files changed, 41 insertions(+), 29 deletions(-) diff --git a/js/src/geo/BboxVectorSource.js b/js/src/geo/BboxVectorSource.js index f0721ff..e1051b0 100644 --- a/js/src/geo/BboxVectorSource.js +++ b/js/src/geo/BboxVectorSource.js @@ -1,7 +1,7 @@ import VectorSource from 'ol/source/Vector.js'; import { bbox } from 'ol/loadingstrategy'; -import { transformToLatLonExtent } from './OpenLayersUtils.js'; +import { transformToEpsg4326LatLonExtent } from './OpenLayersUtils.js'; export default class BboxVectorSource extends VectorSource { constructor(options) { @@ -11,7 +11,7 @@ export default class BboxVectorSource extends VectorSource { static processOptions(options) { options.strategy = bbox; options.url = function(extent, resolution, projection) { - var bbox = transformToLatLonExtent(extent, projection); + var bbox = transformToEpsg4326LatLonExtent(extent, projection); const baseUrl = options.baseUrl; // invert bbox order in order to have minLat,minLon,maxLat,maxLon as required by WFS 2.0.0 diff --git a/js/src/geo/OpenLayersMapPart.js b/js/src/geo/OpenLayersMapPart.js index a31bc21..d033e30 100644 --- a/js/src/geo/OpenLayersMapPart.js +++ b/js/src/geo/OpenLayersMapPart.js @@ -3,7 +3,6 @@ */ import { fromLonLat, getPointResolution } from 'ol/proj.js'; -import { transformExtent } from 'ol/proj.js'; import TileLayer from 'ol/layer/Tile.js'; @@ -21,6 +20,7 @@ import { easeOut } from 'ol/easing'; import * as SLDReader from '@nieuwlandgeo/sldreader'; import MapPart from './MapPart.js'; +import { transformToOlLonLatExtent } from './OpenLayersUtils.js'; /** OpenLayers implementation of MapPart. */ export default class OpenLayersMapPart extends MapPart { @@ -81,7 +81,7 @@ export default class OpenLayersMapPart extends MapPart { } fit(extent, options) { - var transformed = transformExtent(extent, 'EPSG:4326', this.#map.getView().getProjection()); + var transformed = transformToOlLonLatExtent(extent, this.#map.getView().getProjection()); this.#map.getView().fit(transformed, options); } diff --git a/js/src/geo/OpenLayersUtils.js b/js/src/geo/OpenLayersUtils.js index d223463..b85ad7d 100644 --- a/js/src/geo/OpenLayersUtils.js +++ b/js/src/geo/OpenLayersUtils.js @@ -1,7 +1,7 @@ import { transformExtent } from 'ol/proj.js'; -export function transformToLatLonExtent(extent, projection) { +export function transformToEpsg4326LatLonExtent(extent, projection) { const proj = projection.getCode(); if (proj === 'EPSG:4326') return toLatLonExtent(extent); @@ -9,6 +9,23 @@ export function transformToLatLonExtent(extent, projection) { return toLatLonExtent(transformed); } +/** From EPSG:4326 lat/lon to a proj lon/lat */ +export function transformToOlLonLatExtent(extent, projection) { + const proj = projection.getCode(); + if (proj === 'EPSG:4326') + return toLonLatExtent(extent); + const reordered = toLonLatExtent(extent); + var transformed = transformExtent(reordered, 'EPSG:4326', proj); + return transformed; +} + +/** Converts from an extent in OpenLayers order (lon/lat) to WFS 2.0 order (lat/lon). */ export function toLatLonExtent(extent) { return [extent[1], extent[0], extent[3], extent[2]]; -} \ No newline at end of file +} + +/** Converts from an extent in WFS 2.0 order (lat/lon) to OpenLayers order (lon/lat) . */ +export function toLonLatExtent(extent) { + return [extent[1], extent[0], extent[3], extent[2]]; +} + diff --git a/org.argeo.app.geo/src/org/argeo/app/api/geo/FeatureAdapter.java b/org.argeo.app.geo/src/org/argeo/app/api/geo/FeatureAdapter.java index 03ca1ce..69689a9 100644 --- a/org.argeo.app.geo/src/org/argeo/app/api/geo/FeatureAdapter.java +++ b/org.argeo.app.geo/src/org/argeo/app/api/geo/FeatureAdapter.java @@ -5,11 +5,8 @@ import javax.xml.namespace.QName; import org.argeo.api.acr.Content; import org.argeo.api.acr.search.AndFilter; import org.argeo.app.api.EntityType; -import org.argeo.app.api.WGS84PosName; -import org.argeo.app.geo.JTS; -import org.locationtech.jts.geom.Coordinate; +import org.argeo.app.geo.acr.GeoEntityUtils; import org.locationtech.jts.geom.Geometry; -import org.locationtech.jts.geom.Point; import jakarta.json.stream.JsonGenerator; @@ -29,12 +26,13 @@ public interface FeatureAdapter { static Geometry getGeoPointGeometry(Content c) { if (c.hasContentClass(EntityType.geopoint)) { - double latitude = c.get(WGS84PosName.lat, Double.class).get(); - double longitude = c.get(WGS84PosName.lon, Double.class).get(); - - Coordinate coordinate = new Coordinate(longitude, latitude); - Point the_geom = JTS.GEOMETRY_FACTORY.createPoint(coordinate); - return the_geom; + return GeoEntityUtils.toPoint(c); +// double latitude = c.get(WGS84PosName.lat, Double.class).get(); +// double longitude = c.get(WGS84PosName.lon, Double.class).get(); +// +// Coordinate coordinate = new Coordinate(longitude, latitude); +// Point the_geom = JTS.GEOMETRY_FACTORY.createPoint(coordinate); +// return the_geom; } return null; } diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/GeoJson.java b/org.argeo.app.geo/src/org/argeo/app/geo/GeoJson.java index c1ba1d3..8c4c7b2 100644 --- a/org.argeo.app.geo/src/org/argeo/app/geo/GeoJson.java +++ b/org.argeo.app.geo/src/org/argeo/app/geo/GeoJson.java @@ -93,8 +93,9 @@ public class GeoJson { /** Writes a pair of coordinates [lat,lon]. */ public static void writeCoordinate(JsonGenerator g, Coordinate coordinate) { - g.write(coordinate.getX()); + // !! longitude is first in GeoJSON g.write(coordinate.getY()); + g.write(coordinate.getX()); double z = coordinate.getZ(); if (!Double.isNaN(z)) { g.write(z); @@ -149,13 +150,14 @@ public class GeoJson { return (T) res; } - /** Reads a coordinate sequence [[lat,lon],[lat,lon]]. */ + /** Reads a coordinate pair [lon,lat]. */ public static Coordinate readCoordinate(JsonArray arr) { assert arr.size() >= 2; - return new Coordinate(arr.getJsonNumber(0).doubleValue(), arr.getJsonNumber(1).doubleValue()); + // !! longitude is first in GeoJSon + return new Coordinate(arr.getJsonNumber(1).doubleValue(), arr.getJsonNumber(0).doubleValue()); } - /** Reads a coordinate pair [lat,lon]. */ + /** Reads a coordinate sequence [[lon,lat],[lon,lat]]. */ public static Coordinate[] readCoordinates(JsonArray arr) { Coordinate[] coords = new Coordinate[arr.size()]; for (int i = 0; i < arr.size(); i++) diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/GpxUtils.java b/org.argeo.app.geo/src/org/argeo/app/geo/GpxUtils.java index dcd205a..44afa2c 100644 --- a/org.argeo.app.geo/src/org/argeo/app/geo/GpxUtils.java +++ b/org.argeo.app.geo/src/org/argeo/app/geo/GpxUtils.java @@ -68,7 +68,7 @@ public class GpxUtils { Double latitude = Double.parseDouble(attributes.getValue("lat")); Double longitude = Double.parseDouble(attributes.getValue("lon")); // TODO elevation in 3D context - Coordinate coordinate = new Coordinate(longitude, latitude); + Coordinate coordinate = new Coordinate(latitude, longitude); coordinates.add(coordinate); } } @@ -107,7 +107,7 @@ public class GpxUtils { throw new IllegalArgumentException("Unsupported format " + clss); } } - + /** @deprecated Use {@link #parseGpxTrackTo(InputStream, Class)} instead. */ @Deprecated public static SimpleFeature parseGpxToPolygon(InputStream in) throws IOException { diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/http/WfsHttpHandler.java b/org.argeo.app.geo/src/org/argeo/app/geo/http/WfsHttpHandler.java index 94c3c01..8c143db 100644 --- a/org.argeo.app.geo/src/org/argeo/app/geo/http/WfsHttpHandler.java +++ b/org.argeo.app.geo/src/org/argeo/app/geo/http/WfsHttpHandler.java @@ -34,6 +34,7 @@ import org.argeo.app.geo.GeoJson; import org.argeo.app.geo.GeoUtils; import org.argeo.app.geo.GpxUtils; import org.argeo.app.geo.JTS; +import org.argeo.app.geo.acr.GeoEntityUtils; import org.argeo.cms.acr.json.AcrJsonUtils; import org.argeo.cms.auth.RemoteAuthUtils; import org.argeo.cms.http.HttpHeader; @@ -59,7 +60,6 @@ import org.geotools.wfs.GML.Version; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Envelope; import org.locationtech.jts.geom.Geometry; -import org.locationtech.jts.geom.Point; import org.locationtech.jts.geom.Polygon; import com.sun.net.httpserver.HttpExchange; @@ -361,12 +361,7 @@ public class WfsHttpHandler implements HttpHandler { protected Geometry getDefaultGeometry(Content content) { if (content.hasContentClass(EntityType.geopoint)) { - double latitude = content.get(WGS84PosName.lat, Double.class).get(); - double longitude = content.get(WGS84PosName.lon, Double.class).get(); - - Coordinate coordinate = new Coordinate(longitude, latitude); - Point the_geom = JTS.GEOMETRY_FACTORY.createPoint(coordinate); - return the_geom; + return GeoEntityUtils.toPoint(content); } return null; } -- 2.30.2