diff --git a/.github/spell-ignore-words.txt b/.github/spell-ignore-words.txt index cecdf78c2..511234cba 100644 --- a/.github/spell-ignore-words.txt +++ b/.github/spell-ignore-words.txt @@ -10,3 +10,4 @@ Mapnik Redis CloudFront OpenLayers +pyproj diff --git a/poetry.lock b/poetry.lock index 2909cad59..fe8fe9b4f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3490,4 +3490,4 @@ test = ["zope.testing"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.13" -content-hash = "977c579434bd4b21a46e5bedbbbb39c9fa371f670b88821aaec7fc6049a3861f" +content-hash = "714596af26b818b77392fc5565e4a7dc5f93927aeea6d1a130bb7ecb98ee1226" diff --git a/pyproject.toml b/pyproject.toml index 3d4ed22f8..15a8fede1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,6 +74,7 @@ waitress = "3.0.2" certifi = "2024.8.30" Paste = "3.10.1" psutil = "6.1.0" +pyproj = "3.7.0" [tool.poetry.group.dev.dependencies] prospector = { extras = ["with_mypy", "with_bandit", "with_pyroma", "with_ruff"], version = "1.13.3" } diff --git a/tilecloud_chain/CONFIG.md b/tilecloud_chain/CONFIG.md index 45fd88a9d..927aacee3 100644 --- a/tilecloud_chain/CONFIG.md +++ b/tilecloud_chain/CONFIG.md @@ -23,7 +23,7 @@ - **`postgresql`**: Refer to _[#/definitions/postgresql](#definitions/postgresql)_. - **`openlayers`** _(object)_: Configuration used to generate the OpenLayers example page. Cannot contain additional properties. - **`srs`** _(string)_: The projection code. Default: `"EPSG:2056"`. - - **`proj4js_def`** _(string)_: The `proj4js` definition, get it from https://epsg.io/. Default: `"+proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 +k_0=1 +x_0=2600000 +y_0=1200000 +ellps=bessel +towgs84=674.374,15.056,405.346,0,0,0,0 +units=m +no_defs"`. + - **`proj4js_def`** _(string)_: The `proj4js` definition, by default it will be build with pyproj. - **`center_x`** _(number)_: The center easting. Default: `2600000`. - **`center_y`** _(number)_: The center northing. Default: `1200000`. - **`zoom`** _(number)_: The initial zoom. Default: `3`. diff --git a/tilecloud_chain/configuration.py b/tilecloud_chain/configuration.py index abb70a555..4351148f1 100644 --- a/tilecloud_chain/configuration.py +++ b/tilecloud_chain/configuration.py @@ -1979,9 +1979,7 @@ class Openlayers(TypedDict, total=False): """ Proj4js definition. - The `proj4js` definition, get it from https://epsg.io/ - - default: +proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 +k_0=1 +x_0=2600000 +y_0=1200000 +ellps=bessel +towgs84=674.374,15.056,405.346,0,0,0,0 +units=m +no_defs + The `proj4js` definition, by default it will be build with pyproj """ center_x: int | float @@ -2050,10 +2048,6 @@ class Openlayers(TypedDict, total=False): """ Default value of the field path 'Redis prefix' """ -PROJ4JS_DEFINITION_DEFAULT = "+proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 +k_0=1 +x_0=2600000 +y_0=1200000 +ellps=bessel +towgs84=674.374,15.056,405.346,0,0,0,0 +units=m +no_defs" -""" Default value of the field path 'OpenLayers proj4js_def' """ - - class Phone(TypedDict, total=False): """ Phone. diff --git a/tilecloud_chain/schema.json b/tilecloud_chain/schema.json index 5154ef6ad..9f45dd5d6 100644 --- a/tilecloud_chain/schema.json +++ b/tilecloud_chain/schema.json @@ -1541,9 +1541,8 @@ }, "proj4js_def": { "title": "Proj4js definition", - "description": "The `proj4js` definition, get it from https://epsg.io/", - "type": "string", - "default": "+proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 +k_0=1 +x_0=2600000 +y_0=1200000 +ellps=bessel +towgs84=674.374,15.056,405.346,0,0,0,0 +units=m +no_defs" + "description": "The `proj4js` definition, by default it will be build with pyproj", + "type": "string" }, "center_x": { "title": "Center x", diff --git a/tilecloud_chain/views/admin.py b/tilecloud_chain/views/admin.py index 3fbfbc965..34ebc795b 100644 --- a/tilecloud_chain/views/admin.py +++ b/tilecloud_chain/views/admin.py @@ -31,13 +31,13 @@ import logging import multiprocessing import os -import re import shlex import subprocess # nosec from collections.abc import Callable from typing import IO, Any from urllib.parse import urljoin +import pyproj import pyramid.httpexceptions import pyramid.request import pyramid.response @@ -307,15 +307,13 @@ def admin_test(self) -> dict[str, Any]: assert self.gene config = self.gene.get_host_config(self.request.host) main_config = self.gene.get_main_config() + srs = config.config["openlayers"].get("srs", configuration.SRS_DEFAULT) + proj4js_def = config.config["openlayers"].get("proj4js_def") + if proj4js_def is None: + proj4js_def = pyproj.CRS.from_string(srs).to_proj4() return { - "proj4js_def": re.sub( - r"\s+", - " ", - config.config["openlayers"] - .get("proj4js_def", configuration.PROJ4JS_DEFINITION_DEFAULT) - .strip(), - ), - "srs": config.config["openlayers"].get("srs", configuration.SRS_DEFAULT), + "proj4js_def": proj4js_def, + "srs": srs, "center_x": config.config["openlayers"].get("center_x", configuration.CENTER_X_DEFAULT), "center_y": config.config["openlayers"].get("center_y", configuration.CENTER_Y_DEFAULT), "zoom": config.config["openlayers"].get("zoom", configuration.MAP_INITIAL_ZOOM_DEFAULT),