From c2e2a8b98ae0f0ff8dbc4329e0b86897d773ce3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Satabin?= Date: Tue, 17 Mar 2026 17:50:53 +0100 Subject: [PATCH] =?UTF-8?q?Mise=20en=20conformit=C3=A9=20des=20API=20OGC?= =?UTF-8?q?=20Tiles=20et=20Maps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - API Maps : implémentation intégrée au service OGC API - API Admin : sécurisation par secret - Configuration des services : les options sont regroupées quand elles concernent un même type de service (tuilé par exemple) - API Tiles : il n'est plus vu comme un service séparé mais est intégré au service OGC API - Factorisation du code de calcul d'une image ou d'une tuile - API Common : elle est intégrée au service OGC API --- CHANGELOG.md | 13 + CMakeLists.txt | 3 +- README.md | 88 +- config.h.in | 1 + config/layer.schema.json | 2 +- config/server.schema.json | 5 - config/services.json | 132 +- config/services.schema.json | 391 +- ...gcapi-maps-1-example-1-1.0.0-resolved.yaml | 4225 ++++++++++++++++ ...capi-tiles-1-example-1-1.0.0-resolved.yaml | 4324 +++++++++++++++++ docs/openapi.yaml | 817 +++- src/configurations/Attribution.h | 10 +- src/configurations/Layer.cpp | 245 +- src/configurations/Layer.h | 81 +- src/configurations/Metadata.h | 2 +- src/configurations/Server.cpp | 37 - src/configurations/Server.h | 24 +- src/configurations/Services.cpp | 412 +- src/configurations/Services.h | 106 +- src/{ => core}/DataStreams.h | 2 +- src/{ => core}/Inspire.cpp | 2 +- src/{ => core}/Inspire.h | 0 src/core/Map.h | 318 ++ .../health/Threads.cpp => core/Process.cpp} | 43 +- .../health/Threads.h => core/Process.h} | 65 +- src/{ => core}/Request.cpp | 10 +- src/{ => core}/Request.h | 8 +- src/{ => core}/Rok4Server.cpp | 18 +- src/{ => core}/Rok4Server.h | 60 +- src/core/Tile.h | 156 + src/{ => core}/Utils.h | 2 +- src/main.cpp | 23 +- src/services/Router.cpp | 25 +- src/services/Router.h | 10 +- src/services/Service.cpp | 60 +- src/services/Service.h | 19 +- src/services/admin/Exception.h | 4 +- src/services/admin/Service.cpp | 33 +- src/services/admin/Service.h | 14 +- src/services/admin/layers.cpp | 36 +- src/services/admin/turnonoff.cpp | 10 +- src/services/common/Exception.h | 72 - src/services/common/Service.cpp | 126 - src/services/common/Service.h | 89 - src/services/common/getcapabilities.cpp | 120 - src/services/health/Exception.h | 4 +- src/services/health/Service.cpp | 19 +- src/services/health/Service.h | 10 +- src/services/health/gets.cpp | 24 +- src/services/{common => ogcapi}/Exception.cpp | 12 +- src/services/{tiles => ogcapi}/Exception.h | 14 +- src/services/ogcapi/Service.cpp | 179 + src/services/{tiles => ogcapi}/Service.h | 80 +- .../tilematrixsets.cpp => ogcapi/api.cpp} | 109 +- src/services/ogcapi/capabilities.cpp | 146 + src/services/ogcapi/collections.cpp | 162 + src/services/ogcapi/maps.cpp | 304 ++ src/services/ogcapi/tiles.cpp | 293 ++ src/services/tiles/Exception.cpp | 52 - src/services/tiles/Service.cpp | 196 - src/services/tiles/getcapabilities.cpp | 334 -- src/services/tiles/getfeatureinfo.cpp | 55 - src/services/tiles/gettile.cpp | 278 -- src/services/tms/Exception.h | 4 +- src/services/tms/Service.cpp | 74 +- src/services/tms/Service.h | 19 +- src/services/tms/getcapabilities.cpp | 22 +- src/services/tms/gettile.cpp | 21 +- src/services/wms/Exception.h | 4 +- src/services/wms/Service.cpp | 286 +- src/services/wms/Service.h | 81 +- src/services/wms/getcapabilities.cpp | 28 +- src/services/wms/getfeatureinfo.cpp | 135 +- src/services/wms/getmap.cpp | 175 +- src/services/wmts/Exception.h | 4 +- src/services/wmts/Service.cpp | 103 +- src/services/wmts/Service.h | 45 +- src/services/wmts/getcapabilities.cpp | 10 +- src/services/wmts/getfeatureinfo.cpp | 10 +- src/services/wmts/gettile.cpp | 142 +- 80 files changed, 12243 insertions(+), 3434 deletions(-) create mode 100644 docs/OGC-ogcapi-maps-1-example-1-1.0.0-resolved.yaml create mode 100644 docs/OGC-ogcapi-tiles-1-example-1-1.0.0-resolved.yaml rename src/{ => core}/DataStreams.h (99%) rename src/{ => core}/Inspire.cpp (99%) rename src/{ => core}/Inspire.h (100%) create mode 100644 src/core/Map.h rename src/{services/health/Threads.cpp => core/Process.cpp} (81%) rename src/{services/health/Threads.h => core/Process.h} (82%) rename src/{ => core}/Request.cpp (96%) rename src/{ => core}/Request.h (98%) rename src/{ => core}/Rok4Server.cpp (90%) rename src/{ => core}/Rok4Server.h (84%) create mode 100644 src/core/Tile.h rename src/{ => core}/Utils.h (99%) delete mode 100644 src/services/common/Exception.h delete mode 100644 src/services/common/Service.cpp delete mode 100644 src/services/common/Service.h delete mode 100644 src/services/common/getcapabilities.cpp rename src/services/{common => ogcapi}/Exception.cpp (86%) rename src/services/{tiles => ogcapi}/Exception.h (89%) create mode 100644 src/services/ogcapi/Service.cpp rename src/services/{tiles => ogcapi}/Service.h (55%) rename src/services/{tiles/tilematrixsets.cpp => ogcapi/api.cpp} (54%) create mode 100644 src/services/ogcapi/capabilities.cpp create mode 100644 src/services/ogcapi/collections.cpp create mode 100644 src/services/ogcapi/maps.cpp create mode 100644 src/services/ogcapi/tiles.cpp delete mode 100644 src/services/tiles/Exception.cpp delete mode 100644 src/services/tiles/Service.cpp delete mode 100644 src/services/tiles/getcapabilities.cpp delete mode 100644 src/services/tiles/getfeatureinfo.cpp delete mode 100644 src/services/tiles/gettile.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index f721fbe..8ef98da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,19 @@ Le format est basé sur [Keep a Changelog](https://keepachangelog.com/) et ce pr ## [Unreleased] +### Added +- API Maps : implémentation intégrée au service OGC API +- OGC API : possibilité de filtrer les collections par bbox +- API Admin : sécurisation par secret + +### Changed +- Configuration des services : les options sont regroupées quand elles concernent un même type de service (tuilé par exemple) +- API Tiles : il n'est plus vu comme un service séparé mais est intégré au service OGC API +- Factorisation du code de calcul d'une image ou d'une tuile + +### Removed +- API Common : elle est intégrée au service OGC API + ## [6.2.1] - 2026-06-25 ### Added diff --git a/CMakeLists.txt b/CMakeLists.txt index a76c36d..5a0cb72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ set(BUILD_SHARED_LIBS OFF) ################### PARAMÈTRES set(BUILD_VERSION "0.0.0" CACHE STRING "Build version") -set(CPACK_SYSTEM_NAME "ubuntu-20.04" CACHE STRING "Building OS, to deduce package format to generate") +set(CPACK_SYSTEM_NAME "ubuntu-22.04" CACHE STRING "Building OS, to deduce package format to generate") set(CMAKE_INSTALL_PREFIX "/usr/local" CACHE PATH "Installation location") set(DEBUG_BUILD 0 CACHE BOOL "Debug mode compilation") set(UNITTEST_ENABLED 1 CACHE BOOL "Unit tests compilation") @@ -62,6 +62,7 @@ message(STATUS "Building ROK4 Server") file(GLOB ROK4SERVER_SRCS "${PROJECT_SOURCE_DIR}/src/*.cpp" + "${PROJECT_SOURCE_DIR}/src/core/*.cpp" "${PROJECT_SOURCE_DIR}/src/services/*.cpp" "${PROJECT_SOURCE_DIR}/src/services/*/*.cpp" "${PROJECT_SOURCE_DIR}/src/configurations/*.cpp" diff --git a/README.md b/README.md index c711463..fcf6dda 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ ![ROK4 Logo](https://rok4.github.io/assets/images/rok4-256.png) -Le serveur implémente les standards ouverts de l’Open Geospatial Consortium (OGC) WMS 1.3.0, WMTS 1.0.0 et OGC API Tiles 1.0.0, ainsi que le TMS (Tile Map Service). Il vise deux objectifs principaux : +Le serveur implémente les standards ouverts de l’Open Geospatial Consortium (OGC) WMS 1.3.0, WMTS 1.0.0 et OGC API Tiles et Maps, ainsi que le TMS (Tile Map Service). Il vise deux objectifs principaux : -* L’utilisation d’un cache de données raster unique permettant de servir indifféremment des flux WMS, WMTS, API Tiles et TMS +* L’utilisation d’un cache de données raster unique permettant de servir indifféremment des flux WMS, WMTS, OGC API Tiles et Maps et TMS * Des performances de traitement d’image et de diffusion accrues * La diffusion de tuiles vecteur telles qu'elles sont stockées, sans transformation (TMS uniquement) * La diffusion en WMTS selon des Tile Matrix Sets différents de celui de la pyramide utilisée. @@ -117,6 +117,82 @@ check-jsonschema /path/to/your/server.json --schemafile ./config/server.schema.j check-jsonschema /path/to/your/services.json --schemafile ./config/services.schema.json ``` +#### Convertir la configuration des services v6 -> v7+ + +La commande `jq` suivante permet d'obtenir la structure de la configuration v7+ à partir de la configuration v6 : + +```bash +jq ' + . | + { + enabled: true, + global: { + provider: .provider, + site: .site, + fee: .fee, + access_constraint: .access_constraint, + contact: .contact, + crs_equivalences: .crs_equivalences, + default_style: .default_style, + inspire: .wms.inspire, + map: { + limits: .wms.limits, + formats: .wms.formats, + crs: .wms.crs, + reprojection: .wms.reprojection + }, + tile: { + reprojection: .wmts.reprojection + } + }, + admin: .admin, + health: .health, + wms: { + enabled: .wms.enabled, + endpoint_uri: .wms.endpoint_uri, + root_path: .wms.root_path, + title: .wms.title, + abstract: .wms.abstract, + keywords: .wms.keywords, + metadata: .wms.metadata, + name: .wms.name, + root_layer: .wms.root_layer + }, + wmts: { + enabled: .wmts.enabled, + endpoint_uri: .wmts.endpoint_uri, + root_path: .wmts.root_path, + title: .wmts.title, + abstract: .wmts.abstract, + keywords: .wmts.keywords, + metadata: .wmts.metadata + }, + tms: { + enabled: .tms.enabled, + endpoint_uri: .tms.endpoint_uri, + root_path: .tms.root_path, + title: .tms.title, + abstract: .tms.abstract, + keywords: .tms.keywords, + metadata: .tms.metadata + }, + ogcapi: { + enabled: .tiles.enabled, + endpoint_uri: (.tiles.endpoint_uri | sub("/tiles"; "/ogcapi")), + root_path: "/ogcapi", + title: (.tiles.title | sub(" Tiles"; "")), + abstract: (.tiles.abstract | sub(" Tiles"; "")), + keywords: .tiles.keywords, + metadata: .tiles.metadata, + tiles: true, + maps: true, + default_size: 256 + } + } +' services.json +``` + + ### Lancer le serveur #### En ligne de commande @@ -176,7 +252,7 @@ On redémarre nginx : `systemctl restart nginx` - WMS : http://localhost/rok4/wms?request=GetCapabilities&service=WMS - WMTS : http://localhost/rok4/wmts?request=GetCapabilities&service=WMTS - TMS : http://localhost/rok4/tms/1.0.0 - - OGC API Tiles : http://localhost/rok4/tiles/collections + - OGC API : http://localhost/rok4/ogcapi/collections * Racine de l'API d'administration : http://localhost/rok4/admin/ * État de santé du serveur : http://localhost/rok4/healthcheck @@ -190,7 +266,7 @@ Lorsque le serveur reçoit une requête, c'est le premier élément du chemin qu * `/healthcheck` -> requête d'état de santé ou statut du serveur * `/wmts` -> requête WMTS * `/wms` -> requête WMS -* `/tiles` -> requête API Tiles +* `/ogcapi` -> requête OGC API * `/tms` -> requête TMS * `/admin` -> requête d'administration @@ -241,8 +317,8 @@ Pour que les URLs présentes dans les réponses des services soient correctes ma "tms": { "endpoint_uri": "http://localhost/rok4/tms" }, - "tiles": { - "endpoint_uri": "http://localhost/rok4/tiles" + "ogcapi": { + "endpoint_uri": "http://localhost/rok4/ogcapi" } ``` diff --git a/config.h.in b/config.h.in index 002c3f7..f27db3e 100644 --- a/config.h.in +++ b/config.h.in @@ -61,5 +61,6 @@ #define DEFAULT_LOG_LEVEL boost::log::trivial::error #define DEFAULT_NB_THREAD 1 #define DEFAULT_RESAMPLING "lanczos_2" +#define SECRET_HEADER_NAME "HTTP_X_ROK4_SECRET" diff --git a/config/layer.schema.json b/config/layer.schema.json index 153d2a1..934dc09 100644 --- a/config/layer.schema.json +++ b/config/layer.schema.json @@ -210,7 +210,7 @@ } } }, - "tiles": { + "ogcapi": { "type": "object", "properties": { "enabled": { diff --git a/config/server.schema.json b/config/server.schema.json index 3d6bbd3..e7824c2 100644 --- a/config/server.schema.json +++ b/config/server.schema.json @@ -16,11 +16,6 @@ "type": "integer", "description": "Socket's backlog size" }, - "enabled": { - "type": "boolean", - "description": "Broadcast activation when all configuration is loaded", - "default": true - }, "logger": { "type": "object", "description": "Logger configuration", diff --git a/config/services.json b/config/services.json index d931a0b..493c1d4 100644 --- a/config/services.json +++ b/config/services.json @@ -1,105 +1,105 @@ { - "provider": "Local", - "site": "http://localhost", - "fee": "none", - "access_constraint": "none", - "contact": { - "name": "SAV", - "position": "custodian", - "voice": "", - "facsimile": "", - "address_type": "", - "delivery_point": "", - "city": "", - "administrative_area": "", - "post_code": "", - "country": "", - "email": "" + "enabled": true, + "global": { + "provider": "Local", + "site": "http://localhost", + "fee": "none", + "access_constraint": "none", + "contact": { + "name": "SAV", + "position": "custodian", + "voice": "", + "facsimile": "", + "address_type": "", + "delivery_point": "", + "city": "", + "administrative_area": "", + "post_code": "", + "country": "", + "email": "" + }, + "crs_equivalences": "/etc/rok4/equals_crs.json", + "default_style": "normal", + "inspire": true, + "map": { + "limits": { + "width": 10000, + "height": 10000, + "tile_x": 256, + "tile_y": 256, + "layers_count": 2 + }, + "formats": [ + "image/jpeg", + "image/png", + "image/tiff", + "image/geotiff", + "image/x-bil;bits=32" + ], + "crs": [ + "CRS:84", + "EPSG:3857", + "EPSG:4326" + ], + "reprojection": true + }, + "tile": { + "reprojection": true + } }, - "crs_equivalences": "/etc/rok4/equals_crs.json", - "default_style": "normal", "admin": { - "enabled": true + "enabled": true, + "secret": "password" }, "health": { "enabled": true }, - "common": { - "enabled": true, - "endpoint_uri": "http://localhost/rok4/common", - "root_path": "/common", - "title": "Service COMMON", - "abstract": "Ce service permet la découvertes des services assurés par ce serveur", - "keywords": [ - "COMMON" - ] - }, "wms": { "enabled": true, "endpoint_uri": "http://localhost/rok4/wms", "root_path": "/wms", - "title": "Service de visualisation WMS", - "abstract": "Ce service permet la visulation de couches de données raster IGN au travers d'un flux WMS", - "keywords": [ - "WMS" - ], - "limits": { - "width": 10000, - "height": 10000, - "tile_x": 256, - "tile_y": 256, - "layers_count": 2 - }, - "name": "WMS", - "formats": [ - "image/jpeg", - "image/png", - "image/tiff", - "image/geotiff", - "image/x-bil;bits=32" - ], - "crs": [ - "CRS:84", - "EPSG:3857", - "EPSG:4326" - ], "root_layer": { "title": "Couches WMS", "abstract": "Données servies en WMS" }, - "reprojection": true, - "inspire": false + "name": "WMS", + "title": "Service de visualisation WMS", + "abstract": "Ce service permet la visulation de couches de données raster au travers d'un flux WMS", + "keywords": [ + "WMS" + ] }, "wmts": { "enabled": true, "endpoint_uri": "http://localhost/rok4/wmts", "title": "Service de visualisation WMTS", - "abstract": "Ce service permet la visulation de couches de données raster IGN au travers d'un flux WMTS", + "abstract": "Ce service permet la visulation de couches de données raster au travers d'un flux WMTS", "keywords": [ "WMTS" ], - "root_path": "/wmts", - "reprojection": true + "root_path": "/wmts" }, "tms": { "enabled": true, "endpoint_uri": "http://localhost/rok4/tms", "root_path": "/tms", "title": "Service de visualisation TMS", - "abstract": "Ce service permet la visulation de couches de données raster IGN au travers d'un flux TMS", + "abstract": "Ce service permet la visulation de couches de données au travers d'un flux TMS", "keywords": [ "TMS" ] }, - "tiles": { + "ogcapi": { "enabled": true, - "endpoint_uri": "http://localhost/rok4/tiles", - "root_path": "/tiles", - "title": "Service de visualisation OGC API Tiles", - "abstract": "Ce service permet la visulation de couches de données raster IGN au travers d'un flux OGC API Tiles", + "endpoint_uri": "http://localhost/rok4/ogcapi", + "root_path": "/ogcapi", + "title": "Service de visualisation selon les API OGC", + "abstract": "Ce service permet la visulation de couches de données au travers de flux OGC API Tiles", "keywords": [ "OGC API Tiles" ], - "reprojection": true + "tiles": true, + "maps": true, + "default_size": 256 } } \ No newline at end of file diff --git a/config/services.schema.json b/config/services.schema.json index bc8c2ba..5ff0e73 100644 --- a/config/services.schema.json +++ b/config/services.schema.json @@ -3,76 +3,180 @@ "title": "ROK4 Services configuration", "type": "object", "additionalProperties": false, - "required": [ - "contact" - ], "properties": { - "provider": { - "type": "string", - "description": "Service provider" + "enabled": { + "type": "boolean", + "description": "Broadcast activation when all configuration is loaded", + "default": true }, - "site": { - "type": "string", - "description": "Provider's website" - }, - "fee": { - "type": "string", - "description": "Access costs" - }, - "access_constraint": { - "type": "string", - "description": "Access conditions" - }, - "crs_equivalences": { - "type": "string", - "description": "Path to JSON file with identical CRS (to avoid useless tranformation)" - }, - "default_style": { - "type": "string", - "description": "Default style internal identifier", - "default": "normal" - }, - "contact": { + "global": { "type": "object", "additionalProperties": false, - "description": "Provider's contact informations", + "required": [ + "contact" + ], "properties": { - "name": { - "type": "string" - }, - "position": { - "type": "string" + "provider": { + "type": "string", + "description": "Service provider" }, - "voice": { - "type": "string" + "site": { + "type": "string", + "description": "Provider's website" }, - "facsimile": { - "type": "string" + "fee": { + "type": "string", + "description": "Access costs" }, - "address_type": { - "type": "string" + "access_constraint": { + "type": "string", + "description": "Access conditions" }, - "delivery_point": { - "type": "string" + "crs_equivalences": { + "type": "string", + "description": "Path to JSON file with identical CRS (to avoid useless tranformation)" }, - "city": { - "type": "string" + "default_style": { + "type": "string", + "description": "Default style internal identifier", + "default": "normal" }, - "administrative_area": { - "type": "string" + "inspire": { + "type": "boolean", + "description": "Inspire mode as default response mode activation", + "default": false }, - "post_code": { - "type": "string" + "contact": { + "type": "object", + "additionalProperties": false, + "description": "Provider's contact informations", + "properties": { + "name": { + "type": "string" + }, + "position": { + "type": "string" + }, + "voice": { + "type": "string" + }, + "facsimile": { + "type": "string" + }, + "address_type": { + "type": "string" + }, + "delivery_point": { + "type": "string" + }, + "city": { + "type": "string" + }, + "administrative_area": { + "type": "string" + }, + "post_code": { + "type": "string" + }, + "country": { + "type": "string" + }, + "email": { + "type": "string" + } + } }, - "country": { - "type": "string" + "tile": { + "type": "object", + "additionalProperties": false, + "description": "Configuration for tile broadcast (WMT, TMS and OGC API Tiles)", + "properties": { + "reprojection": { + "type": "boolean", + "default": false, + "description": "WMTS reprojection activation" + } + } }, - "email": { - "type": "string" + "map": { + "type": "object", + "additionalProperties": false, + "description": "Configuration for map broadcast (WMS and OGC API Maps)", + "properties": { + "formats": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "image/jpeg", + "image/png", + "image/tiff", + "image/geotiff", + "image/x-bil;bits=32", + "text/asc" + ] + }, + "description": "WMS handled raster formats", + "default": [ + "image/jpeg", + "image/png", + "image/tiff", + "image/geotiff", + "image/x-bil;bits=32" + ] + }, + "limits": { + "type": "object", + "additionalProperties": false, + "properties": { + "layers_count": { + "type": "integer", + "description": "Maximum layers count in a WMS GetMap", + "minimum": 1, + "default": 1 + }, + "width": { + "type": "integer", + "description": "Maximum width in a WMS GetMap", + "minimum": 1, + "default": 5000 + }, + "height": { + "type": "integer", + "description": "Maximum height in a WMS GetMap", + "minimum": 1, + "default": 5000 + }, + "tile_x": { + "type": "integer", + "description": "Maximum source tiles count widthwise to build the response of a WMS GetMap", + "minimum": 1, + "default": 32 + }, + "tile_y": { + "type": "integer", + "description": "Maximum source tiles count heightwise to build the response of a WMS GetMap", + "minimum": 1, + "default": 32 + } + } + }, + "crs": { + "type": "array", + "items": { + "type": "string" + }, + "description": "WMS global handled CRS" + }, + "reprojection": { + "type": "boolean", + "default": false, + "description": "WMS reprojection activation" + } + } } } }, - "health": { "type": "object", "additionalProperties": false, @@ -85,7 +189,6 @@ } } }, - "admin": { "type": "object", "additionalProperties": false, @@ -95,50 +198,13 @@ "type": "boolean", "default": false, "description": "Administration API activation" - } - } - }, - - "common": { - "type": "object", - "additionalProperties": false, - "description": "Common service configuration", - "properties": { - "enabled": { - "type": "boolean", - "default": false, - "description": "Common API activation" - }, - "title": { - "type": "string", - "description": "Common API title", - "default": "COMMON service" - }, - "abstract": { - "type": "string", - "description": "Common API abstract", - "default": "COMMON service" - }, - "endpoint_uri": { - "type": "string", - "description": "Common API public endpoint", - "default": "http://localhost/common" }, - "root_path": { + "secret": { "type": "string", - "description": "Common API internal path", - "default": "/common" - }, - "keywords": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Common API keywords" + "description": "Secret token to use the administration API, no security if not provided or empty string" } } }, - "wms": { "type": "object", "additionalProperties": false, @@ -185,38 +251,6 @@ "$ref": "#/$defs/metadata", "description": "WMS service's metadata" }, - "reprojection": { - "type": "boolean", - "default": false, - "description": "WMS reprojection activation" - }, - "inspire": { - "type": "boolean", - "default": false, - "description": "Inspire mode as WMS default response mode activation" - }, - "formats": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "image/jpeg", - "image/png", - "image/tiff", - "image/geotiff", - "image/x-bil;bits=32", - "text/asc" - ] - }, - "description": "WMS handled raster formats", - "default": [ - "image/jpeg", - "image/png", - "image/tiff", - "image/geotiff", - "image/x-bil;bits=32" - ] - }, "root_layer": { "type": "object", "additionalProperties": false, @@ -231,53 +265,9 @@ "default": "WMS layers" } } - }, - "limits": { - "type": "object", - "additionalProperties": false, - "properties": { - "layers_count": { - "type": "integer", - "description": "Maximum layers count in a WMS GetMap", - "minimum": 1, - "default": 1 - }, - "width": { - "type": "integer", - "description": "Maximum width in a WMS GetMap", - "minimum": 1, - "default": 5000 - }, - "height": { - "type": "integer", - "description": "Maximum height in a WMS GetMap", - "minimum": 1, - "default": 5000 - }, - "tile_x": { - "type": "integer", - "description": "Maximum source tiles count widthwise to build the response of a WMS GetMap", - "minimum": 1, - "default": 32 - }, - "tile_y": { - "type": "integer", - "description": "Maximum source tiles count heightwise to build the response of a WMS GetMap", - "minimum": 1, - "default": 32 - } - } - }, - "crs": { - "type": "array", - "items": { - "type": "string" - }, - "description": "WMS global handled CRS" } } }, - "wmts": { "type": "object", "additionalProperties": false, @@ -318,20 +308,9 @@ "metadata": { "$ref": "#/$defs/metadata", "description": "WMTS service's metadata" - }, - "reprojection": { - "type": "boolean", - "default": false, - "description": "WMTS reprojection activation" - }, - "inspire": { - "type": "boolean", - "default": false, - "description": "Inspire mode as WMTS default response mode activation" } } }, - "tms": { "type": "object", "additionalProperties": false, @@ -375,62 +354,76 @@ } } }, - - "tiles": { + "ogcapi": { "type": "object", "additionalProperties": false, - "description": "OGC API Tiles configuration", + "description": "OGC API configuration", "properties": { "enabled": { "type": "boolean", "default": false, - "description": "OGC API Tiles activation" + "description": "OGC API activation" }, "title": { "type": "string", - "description": "OGC API Tiles title", - "default": "TMS service" + "description": "OGC API title", + "default": "OGC API service" }, "abstract": { "type": "string", - "description": "OGC API Tiles abstract", - "default": "TMS service" + "description": "OGC API abstract", + "default": "OGC API service" }, "endpoint_uri": { "type": "string", - "description": "OGC API Tiles public endpoint", - "default": "http://localhost/tiles" + "description": "OGC API public endpoint", + "default": "http://localhost/ogcapi" }, "root_path": { "type": "string", - "description": "OGC API Tiles internal path", - "default": "/tiles" + "description": "OGC API internal path", + "default": "/ogcapi" }, "keywords": { "type": "array", "items": { "type": "string" }, - "description": "OGC API Tiles keywords" + "description": "OGC API keywords" }, "metadata": { "$ref": "#/$defs/metadata", - "description": "OGC API Tiles service's metadata" + "description": "OGC API service's metadata" }, - "reprojection": { + "tiles": { "type": "boolean", - "default": false, - "description": "OGC API Tiles reprojection activation" + "default": true, + "description": "OGC API Tiles activation" + }, + "maps": { + "type": "boolean", + "default": true, + "description": "OGC API Maps activation" + }, + "default_size": { + "type": "integer", + "minimum": 64, + "maximum": 4096, + "default": 256, + "description": "Default dimension (width or height) for API Maps" } } } }, - "$defs": { "metadata": { "type": "object", "additionalProperties": false, - "required": ["format", "type", "url"], + "required": [ + "format", + "type", + "url" + ], "properties": { "format": { "type": "string", diff --git a/docs/OGC-ogcapi-maps-1-example-1-1.0.0-resolved.yaml b/docs/OGC-ogcapi-maps-1-example-1-1.0.0-resolved.yaml new file mode 100644 index 0000000..74c09c3 --- /dev/null +++ b/docs/OGC-ogcapi-maps-1-example-1-1.0.0-resolved.yaml @@ -0,0 +1,4225 @@ +openapi: 3.0.0 +info: + title: Building blocks specified in the OGC API - Maps Standard + description: "Example API Definition for OGC API - Maps - Part 1: Core" + contact: + name: Open Geospatial Consortium + email: info@ogc.org + license: + name: OGC License + url: http://www.opengeospatial.org/legal/ + version: 1.0.0 +servers: +- url: https://maps.gnosis.earth/ogcapi + description: Example OGC API - Maps server +paths: + /: + get: + tags: + - Landing Page + summary: Retrieve the OGC API landing page for this service. + operationId: getLandingPage + parameters: + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/LandingPage" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /conformance: + get: + tags: + - Conformance + summary: Retrieve the set of OGC API conformance classes that are supported by this service. + operationId: getConformance + parameters: + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/Conformance" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /api: + get: + tags: + - API + summary: Retrieve this API definition. + operationId: getAPI + parameters: + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/API" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /api/all-collections: + get: + tags: + - API + summary: Retrieve the list of collections available from this API implementation & deployment. + operationId: getAPICollections + parameters: + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/Enumeration" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /api/tileMatrixSets: + get: + tags: + - API + summary: JSON enumeration of the shared TileMatrixSets available from this API implementation & deployment (for inclusion in the API definition). + operationId: getAPITileMatrixSets + parameters: + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/Enumeration" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /api/styles: + get: + tags: + - API + summary: Retrieve the list of dataset styles available from this API implementation & deployment. + operationId: getAPIStyles + parameters: + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/Enumeration" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections: + get: + tags: + - Data Collections + summary: Retrieve the list of geospatial data collections available from this service. + operationId: getCollectionsList + parameters: + - name: datetime + in: query + description: |- + Either a date-time or an interval. Date and time expressions adhere to RFC 3339, section 5.6. Intervals may be bounded or half-bounded (double-dots at start or end). Server implementations may or may not support times expressed using time offsets from UTC, but need to support UTC time with the notation ending with a Z. + Examples: + * A date-time: "2018-02-12T23:20:50Z" * A bounded interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" * Half-bounded intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z" + Only resources that have a temporal property that intersects the value of `datetime` are selected. + If a feature has multiple temporal properties, it is the decision of the server whether only a single temporal property is used to determine the extent or all relevant temporal properties. + required: false + style: form + explode: false + schema: + type: string + - name: bbox + in: query + description: |- + Only resources that have a geometry that intersects the bounding box are selected. The bounding box is provided as four or six numbers, depending on whether the coordinate reference system includes a vertical axis (elevation or depth): + * Lower left corner, coordinate axis 1 * Lower left corner, coordinate axis 2 * Minimum value, coordinate axis 3 (optional) * Upper right corner, coordinate axis 1 * Upper right corner, coordinate axis 2 * Maximum value, coordinate axis 3 (optional) + If the value consists of four numbers, the coordinate reference system is WGS84 longitude/latitude (http://www.opengis.net/def/crs/OGC/1.3/CRS84) unless a different coordinate reference system is specified in the parameter `bbox-crs`. + If the value consists of six numbers, the coordinate reference system is WGS 84 longitude/latitude/ellipsoidal height (http://www.opengis.net/def/crs/OGC/0/CRS84h) unless a different coordinate reference system is specified in a parameter `bbox-crs`. + For WGS84 longitude/latitude the values are in most cases the sequence of minimum longitude, minimum latitude, maximum longitude and maximum latitude. However, in cases where the box spans the antimeridian the first value (west-most box edge) is larger than the third value (east-most box edge). + If the vertical axis is included, the third and the sixth number are the bottom and the top of the 3-dimensional bounding box. + If a resource has multiple spatial geometry properties, it is the decision of the server whether only a single spatial geometry property is used to determine the extent or all relevant geometries. + required: false + style: form + explode: false + schema: + type: array + items: + type: number + - name: limit + in: query + description: |- + The optional limit parameter limits the number of collections that are presented in the response document. + Only items are counted that are on the first level of the collection in the response document. Nested objects contained within the explicitly requested items shall not be counted. + * Minimum = 1 * Maximum = 10000 * Default = 10 + required: false + style: form + explode: false + schema: + maximum: 10000 + minimum: 1 + type: integer + default: 10 + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/CollectionsList" + /collections/{collectionId}: + get: + tags: + - Data Collections + summary: Retrieve the description of a collection available from this service. + operationId: getCollection + parameters: + - name: collectionId + in: path + description: Local identifier of a collection + required: true + schema: + $ref: "#/components/schemas/all-collections" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/Collection" + /map: + get: + tags: + - Maps + summary: Retrieve a default map of the whole dataset + operationId: .dataset.getMap + parameters: + - name: bbox + in: query + description: |- + Only resources that have a geometry that intersects the bounding box are selected. The bounding box is provided as four or six numbers, depending on whether the coordinate reference system includes a vertical axis (elevation or depth): + * Lower left corner, coordinate axis 1 * Lower left corner, coordinate axis 2 * Minimum value, coordinate axis 3 (optional) * Upper right corner, coordinate axis 1 * Upper right corner, coordinate axis 2 * Maximum value, coordinate axis 3 (optional) + If the value consists of four numbers, the coordinate reference system is WGS84 longitude/latitude (http://www.opengis.net/def/crs/OGC/1.3/CRS84) unless a different coordinate reference system is specified in the parameter `bbox-crs`. + If the value consists of six numbers, the coordinate reference system is WGS 84 longitude/latitude/ellipsoidal height (http://www.opengis.net/def/crs/OGC/0/CRS84h) unless a different coordinate reference system is specified in a parameter `bbox-crs`. + For WGS84 longitude/latitude the values are in most cases the sequence of minimum longitude, minimum latitude, maximum longitude and maximum latitude. However, in cases where the box spans the antimeridian the first value (west-most box edge) is larger than the third value (east-most box edge). + If the vertical axis is included, the third and the sixth number are the bottom and the top of the 3-dimensional bounding box. + If a resource has multiple spatial geometry properties, it is the decision of the server whether only a single spatial geometry property is used to determine the extent or all relevant geometries. + required: false + style: form + explode: false + schema: + type: array + items: + type: number + - name: datetime + in: query + description: |- + Either a date-time or an interval. Date and time expressions adhere to RFC 3339, section 5.6. Intervals may be bounded or half-bounded (double-dots at start or end). Server implementations may or may not support times expressed using time offsets from UTC, but need to support UTC time with the notation ending with a Z. + Examples: + * A date-time: "2018-02-12T23:20:50Z" * A bounded interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" * Half-bounded intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z" + Only resources that have a temporal property that intersects the value of `datetime` are selected. + If a feature has multiple temporal properties, it is the decision of the server whether only a single temporal property is used to determine the extent or all relevant temporal properties. + required: false + style: form + explode: false + schema: + type: string + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + - name: subset + in: query + description: | + Retrieve only part of the data by slicing or trimming along one or more axis + For trimming: {axisAbbrev}({low}:{high}) (preserves dimensionality) + For slicing: {axisAbbrev}({value}) (reduces dimensionality) + An asterisk (`*`) can be used instead of {low} or {high} to indicate the minimum/maximum value. + For a temporal dimension, a single asterisk can be used to indicate the high value. + Support for `*` is required for time, but optional for spatial and other dimensions. + required: false + style: form + explode: false + schema: + type: array + items: + type: string + - name: crs + in: query + description: reproject the output to the given crs + required: false + style: form + explode: true + schema: + type: string + - name: bbox-crs + in: query + description: crs for the specified bbox + required: false + style: form + explode: true + schema: + type: string + - name: subset-crs + in: query + description: crs for the specified subset + required: false + style: form + explode: true + schema: + type: string + - name: bgcolor + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the background color (default to 0x9C9C9C gray). If alpha is not specified, full opacity is assumed." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + - name: transparent + in: query + description: "Background transparency of map (defaults to `true` without a `bgcolor` specified, but to `false` when a `bgcolor` is used)." + required: false + style: form + explode: false + schema: + type: boolean + default: true + - name: void-color + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the void color for parts of the map outside of the valid area of the projection / CRS. If not specified, this defaults to the same as `bgcolor`." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + - name: void-transparent + in: query + description: Background transparency for parts of the map outside of the valid areas of the CRS / projection (defaults to the same as `transparent` if not specified). + required: false + style: form + explode: false + schema: + type: boolean + default: true + - name: width + in: query + description: "Width of the map in pixels. If omitted and `height` is specified, defaults to the width maintaining a 1:1 aspect ratio. If both `width` and `height` are omitted, the server will select default dimensions. When used together with the `center` and/or `scale-denominator` parameter, `width` takes on a subsetting role rather than scaling (resampling), defining the horizontal portion of the map to subset based on the scale (native scale, or specified by `scale-denominator`) and display resolution (0.28 mm/pixel, or specified by `mm-per-pixel`)." + required: false + style: form + explode: false + schema: + type: integer + - name: height + in: query + description: "Height of the map in pixels. If omitted and `width` is specified, defaults to the height maintaining a 1:1 aspect ratio. If both `width` and `height` are omitted, the server will select default dimensions. When used together with the `center` and/or `scale-denominator` parameter, `height` takes on a subsetting role rather than scaling (resampling), defining the vertical portion of the map to subset based on the scale (native scale, or specified by `scale-denominator`) and display resolution (0.28 mm/pixel, or specified by `mm-per-pixel`)." + required: false + style: form + explode: false + schema: + type: integer + - name: center + in: query + description: "Coordinates of center point for subsetting, in conjunction with the `width` and/or `height` parameters, taking into consideration the scale and display resolution of the map. The center coordinates are comma-separated and interpreted as [ogc:CRS84], unless the `center-crs` parameter specifies otherwise." + required: false + style: form + explode: false + schema: + maxItems: 2 + minItems: 2 + type: array + items: + type: number + - name: center-crs + in: query + description: CRS for the specified center point + required: false + style: form + explode: true + schema: + type: string + - name: scale-denominator + in: query + description: "Scale denominator of the map specifying to how many units in the real world one of the same unit on the map corresponds, as printed or displayed, taking into account the display resolution (`mm-per-pixel` or 0.28 mm/pixel default). This parameter can only be used together with the `width` or `height` parameters (which provide an alternative mechanism to control the scale) if the implementation also supports subsetting, in which case those `width` and `height` parameters then control the subset of the map returned rather than the scale. If `scale-denominator` is omitted, the scale is implied from the dimensions of the returned map compared to its spatial subset area." + required: false + style: form + explode: false + schema: + type: number + - name: mm-per-pixel + in: query + description: "Display resolution of the target rendering device in millimeters per pixel. This parameter controls the relationship between the dimensions of the resulting map in pixels and the scale of the map. The display resolution is taken into account for applying symbology rules, for the `scale-denominator` parameter, and for the spatial subsetting using a `center`, `width` and `height` parameters." + required: false + style: form + explode: false + schema: + type: number + default: 0.28 + - name: orientation + in: query + description: "Orientation in degrees by which the content of the map is to be rotated around the center of the subset area as pivot point in a counter-clockwise direction, resulting in the viewing perspective being rotated by the same orientation in a clockwise direction." + required: false + style: form + explode: false + schema: + type: number + default: 0 + - name: crs-proj-method + in: query + description: Projection operation method for a custom projection CRS. + required: false + style: form + explode: false + schema: + type: string + - name: crs-proj-center + in: query + description: Projection center for a custom projection CRS corresponding to specific projection operation method parameters for latitude and longitude. + required: false + style: form + explode: false + schema: + type: string + - name: crs-proj-params + in: query + description: Operation method parameters for a custom projection CRS. + required: false + style: form + explode: false + schema: + type: string + - name: crs-datum + in: query + description: "Datum for a custom projection CRS, implying a particular ellipsoid." + required: false + style: form + explode: false + schema: + type: string + - name: f + in: query + description: "The format of the map response (e.g. png). Accepted values are 'png', 'jpg' or 'tiff' (GeoTIFF)." + required: false + style: form + explode: false + schema: + type: string + enum: + - png + - jpg + - tiff + responses: + "200": + $ref: "#/components/responses/Map" + "204": + $ref: "#/components/responses/EmptyMap" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /styles/{styleId}/map: + get: + tags: + - Maps + summary: Retrieve a styled map of the whole dataset + operationId: .dataset.style.getMap + parameters: + - name: bbox + in: query + description: |- + Only resources that have a geometry that intersects the bounding box are selected. The bounding box is provided as four or six numbers, depending on whether the coordinate reference system includes a vertical axis (elevation or depth): + * Lower left corner, coordinate axis 1 * Lower left corner, coordinate axis 2 * Minimum value, coordinate axis 3 (optional) * Upper right corner, coordinate axis 1 * Upper right corner, coordinate axis 2 * Maximum value, coordinate axis 3 (optional) + If the value consists of four numbers, the coordinate reference system is WGS84 longitude/latitude (http://www.opengis.net/def/crs/OGC/1.3/CRS84) unless a different coordinate reference system is specified in the parameter `bbox-crs`. + If the value consists of six numbers, the coordinate reference system is WGS 84 longitude/latitude/ellipsoidal height (http://www.opengis.net/def/crs/OGC/0/CRS84h) unless a different coordinate reference system is specified in a parameter `bbox-crs`. + For WGS84 longitude/latitude the values are in most cases the sequence of minimum longitude, minimum latitude, maximum longitude and maximum latitude. However, in cases where the box spans the antimeridian the first value (west-most box edge) is larger than the third value (east-most box edge). + If the vertical axis is included, the third and the sixth number are the bottom and the top of the 3-dimensional bounding box. + If a resource has multiple spatial geometry properties, it is the decision of the server whether only a single spatial geometry property is used to determine the extent or all relevant geometries. + required: false + style: form + explode: false + schema: + type: array + items: + type: number + - name: datetime + in: query + description: |- + Either a date-time or an interval. Date and time expressions adhere to RFC 3339, section 5.6. Intervals may be bounded or half-bounded (double-dots at start or end). Server implementations may or may not support times expressed using time offsets from UTC, but need to support UTC time with the notation ending with a Z. + Examples: + * A date-time: "2018-02-12T23:20:50Z" * A bounded interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" * Half-bounded intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z" + Only resources that have a temporal property that intersects the value of `datetime` are selected. + If a feature has multiple temporal properties, it is the decision of the server whether only a single temporal property is used to determine the extent or all relevant temporal properties. + required: false + style: form + explode: false + schema: + type: string + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + - name: subset + in: query + description: | + Retrieve only part of the data by slicing or trimming along one or more axis + For trimming: {axisAbbrev}({low}:{high}) (preserves dimensionality) + For slicing: {axisAbbrev}({value}) (reduces dimensionality) + An asterisk (`*`) can be used instead of {low} or {high} to indicate the minimum/maximum value. + For a temporal dimension, a single asterisk can be used to indicate the high value. + Support for `*` is required for time, but optional for spatial and other dimensions. + required: false + style: form + explode: false + schema: + type: array + items: + type: string + - name: crs + in: query + description: reproject the output to the given crs + required: false + style: form + explode: true + schema: + type: string + - name: bbox-crs + in: query + description: crs for the specified bbox + required: false + style: form + explode: true + schema: + type: string + - name: subset-crs + in: query + description: crs for the specified subset + required: false + style: form + explode: true + schema: + type: string + - name: bgcolor + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the background color (default to 0x9C9C9C gray). If alpha is not specified, full opacity is assumed." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + - name: transparent + in: query + description: "Background transparency of map (defaults to `true` without a `bgcolor` specified, but to `false` when a `bgcolor` is used)." + required: false + style: form + explode: false + schema: + type: boolean + default: true + - name: void-color + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the void color for parts of the map outside of the valid area of the projection / CRS. If not specified, this defaults to the same as `bgcolor`." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + - name: void-transparent + in: query + description: Background transparency for parts of the map outside of the valid areas of the CRS / projection (defaults to the same as `transparent` if not specified). + required: false + style: form + explode: false + schema: + type: boolean + default: true + - name: width + in: query + description: "Width of the map in pixels. If omitted and `height` is specified, defaults to the width maintaining a 1:1 aspect ratio. If both `width` and `height` are omitted, the server will select default dimensions. When used together with the `center` and/or `scale-denominator` parameter, `width` takes on a subsetting role rather than scaling (resampling), defining the horizontal portion of the map to subset based on the scale (native scale, or specified by `scale-denominator`) and display resolution (0.28 mm/pixel, or specified by `mm-per-pixel`)." + required: false + style: form + explode: false + schema: + type: integer + - name: height + in: query + description: "Height of the map in pixels. If omitted and `width` is specified, defaults to the height maintaining a 1:1 aspect ratio. If both `width` and `height` are omitted, the server will select default dimensions. When used together with the `center` and/or `scale-denominator` parameter, `height` takes on a subsetting role rather than scaling (resampling), defining the vertical portion of the map to subset based on the scale (native scale, or specified by `scale-denominator`) and display resolution (0.28 mm/pixel, or specified by `mm-per-pixel`)." + required: false + style: form + explode: false + schema: + type: integer + - name: center + in: query + description: "Coordinates of center point for subsetting, in conjunction with the `width` and/or `height` parameters, taking into consideration the scale and display resolution of the map. The center coordinates are comma-separated and interpreted as [ogc:CRS84], unless the `center-crs` parameter specifies otherwise." + required: false + style: form + explode: false + schema: + maxItems: 2 + minItems: 2 + type: array + items: + type: number + - name: center-crs + in: query + description: CRS for the specified center point + required: false + style: form + explode: true + schema: + type: string + - name: scale-denominator + in: query + description: "Scale denominator of the map specifying to how many units in the real world one of the same unit on the map corresponds, as printed or displayed, taking into account the display resolution (`mm-per-pixel` or 0.28 mm/pixel default). This parameter can only be used together with the `width` or `height` parameters (which provide an alternative mechanism to control the scale) if the implementation also supports subsetting, in which case those `width` and `height` parameters then control the subset of the map returned rather than the scale. If `scale-denominator` is omitted, the scale is implied from the dimensions of the returned map compared to its spatial subset area." + required: false + style: form + explode: false + schema: + type: number + - name: mm-per-pixel + in: query + description: "Display resolution of the target rendering device in millimeters per pixel. This parameter controls the relationship between the dimensions of the resulting map in pixels and the scale of the map. The display resolution is taken into account for applying symbology rules, for the `scale-denominator` parameter, and for the spatial subsetting using a `center`, `width` and `height` parameters." + required: false + style: form + explode: false + schema: + type: number + default: 0.28 + - name: orientation + in: query + description: "Orientation in degrees by which the content of the map is to be rotated around the center of the subset area as pivot point in a counter-clockwise direction, resulting in the viewing perspective being rotated by the same orientation in a clockwise direction." + required: false + style: form + explode: false + schema: + type: number + default: 0 + - name: crs-proj-method + in: query + description: Projection operation method for a custom projection CRS. + required: false + style: form + explode: false + schema: + type: string + - name: crs-proj-center + in: query + description: Projection center for a custom projection CRS corresponding to specific projection operation method parameters for latitude and longitude. + required: false + style: form + explode: false + schema: + type: string + - name: crs-proj-params + in: query + description: Operation method parameters for a custom projection CRS. + required: false + style: form + explode: false + schema: + type: string + - name: crs-datum + in: query + description: "Datum for a custom projection CRS, implying a particular ellipsoid." + required: false + style: form + explode: false + schema: + type: string + - name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + $ref: "#/components/schemas/styles" + - name: f + in: query + description: "The format of the map response (e.g. png). Accepted values are 'png', 'jpg' or 'tiff' (GeoTIFF)." + required: false + style: form + explode: false + schema: + type: string + enum: + - png + - jpg + - tiff + responses: + "200": + $ref: "#/components/responses/Map" + "204": + $ref: "#/components/responses/EmptyMap" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/map: + get: + tags: + - Maps + summary: Retrieve a map for the specified collection + operationId: .collection.getMap + parameters: + - name: bbox + in: query + description: |- + Only resources that have a geometry that intersects the bounding box are selected. The bounding box is provided as four or six numbers, depending on whether the coordinate reference system includes a vertical axis (elevation or depth): + * Lower left corner, coordinate axis 1 * Lower left corner, coordinate axis 2 * Minimum value, coordinate axis 3 (optional) * Upper right corner, coordinate axis 1 * Upper right corner, coordinate axis 2 * Maximum value, coordinate axis 3 (optional) + If the value consists of four numbers, the coordinate reference system is WGS84 longitude/latitude (http://www.opengis.net/def/crs/OGC/1.3/CRS84) unless a different coordinate reference system is specified in the parameter `bbox-crs`. + If the value consists of six numbers, the coordinate reference system is WGS 84 longitude/latitude/ellipsoidal height (http://www.opengis.net/def/crs/OGC/0/CRS84h) unless a different coordinate reference system is specified in a parameter `bbox-crs`. + For WGS84 longitude/latitude the values are in most cases the sequence of minimum longitude, minimum latitude, maximum longitude and maximum latitude. However, in cases where the box spans the antimeridian the first value (west-most box edge) is larger than the third value (east-most box edge). + If the vertical axis is included, the third and the sixth number are the bottom and the top of the 3-dimensional bounding box. + If a resource has multiple spatial geometry properties, it is the decision of the server whether only a single spatial geometry property is used to determine the extent or all relevant geometries. + required: false + style: form + explode: false + schema: + type: array + items: + type: number + - name: datetime + in: query + description: |- + Either a date-time or an interval. Date and time expressions adhere to RFC 3339, section 5.6. Intervals may be bounded or half-bounded (double-dots at start or end). Server implementations may or may not support times expressed using time offsets from UTC, but need to support UTC time with the notation ending with a Z. + Examples: + * A date-time: "2018-02-12T23:20:50Z" * A bounded interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" * Half-bounded intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z" + Only resources that have a temporal property that intersects the value of `datetime` are selected. + If a feature has multiple temporal properties, it is the decision of the server whether only a single temporal property is used to determine the extent or all relevant temporal properties. + required: false + style: form + explode: false + schema: + type: string + - name: collectionId + in: path + description: Local identifier of a collection + required: true + schema: + $ref: "#/components/schemas/all-collections" + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + - name: subset + in: query + description: | + Retrieve only part of the data by slicing or trimming along one or more axis + For trimming: {axisAbbrev}({low}:{high}) (preserves dimensionality) + For slicing: {axisAbbrev}({value}) (reduces dimensionality) + An asterisk (`*`) can be used instead of {low} or {high} to indicate the minimum/maximum value. + For a temporal dimension, a single asterisk can be used to indicate the high value. + Support for `*` is required for time, but optional for spatial and other dimensions. + required: false + style: form + explode: false + schema: + type: array + items: + type: string + - name: crs + in: query + description: reproject the output to the given crs + required: false + style: form + explode: true + schema: + type: string + - name: bbox-crs + in: query + description: crs for the specified bbox + required: false + style: form + explode: true + schema: + type: string + - name: subset-crs + in: query + description: crs for the specified subset + required: false + style: form + explode: true + schema: + type: string + - name: bgcolor + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the background color (default to 0x9C9C9C gray). If alpha is not specified, full opacity is assumed." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + - name: transparent + in: query + description: "Background transparency of map (defaults to `true` without a `bgcolor` specified, but to `false` when a `bgcolor` is used)." + required: false + style: form + explode: false + schema: + type: boolean + default: true + - name: void-color + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the void color for parts of the map outside of the valid area of the projection / CRS. If not specified, this defaults to the same as `bgcolor`." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + - name: void-transparent + in: query + description: Background transparency for parts of the map outside of the valid areas of the CRS / projection (defaults to the same as `transparent` if not specified). + required: false + style: form + explode: false + schema: + type: boolean + default: true + - name: width + in: query + description: "Width of the map in pixels. If omitted and `height` is specified, defaults to the width maintaining a 1:1 aspect ratio. If both `width` and `height` are omitted, the server will select default dimensions. When used together with the `center` and/or `scale-denominator` parameter, `width` takes on a subsetting role rather than scaling (resampling), defining the horizontal portion of the map to subset based on the scale (native scale, or specified by `scale-denominator`) and display resolution (0.28 mm/pixel, or specified by `mm-per-pixel`)." + required: false + style: form + explode: false + schema: + type: integer + - name: height + in: query + description: "Height of the map in pixels. If omitted and `width` is specified, defaults to the height maintaining a 1:1 aspect ratio. If both `width` and `height` are omitted, the server will select default dimensions. When used together with the `center` and/or `scale-denominator` parameter, `height` takes on a subsetting role rather than scaling (resampling), defining the vertical portion of the map to subset based on the scale (native scale, or specified by `scale-denominator`) and display resolution (0.28 mm/pixel, or specified by `mm-per-pixel`)." + required: false + style: form + explode: false + schema: + type: integer + - name: center + in: query + description: "Coordinates of center point for subsetting, in conjunction with the `width` and/or `height` parameters, taking into consideration the scale and display resolution of the map. The center coordinates are comma-separated and interpreted as [ogc:CRS84], unless the `center-crs` parameter specifies otherwise." + required: false + style: form + explode: false + schema: + maxItems: 2 + minItems: 2 + type: array + items: + type: number + - name: center-crs + in: query + description: CRS for the specified center point + required: false + style: form + explode: true + schema: + type: string + - name: scale-denominator + in: query + description: "Scale denominator of the map specifying to how many units in the real world one of the same unit on the map corresponds, as printed or displayed, taking into account the display resolution (`mm-per-pixel` or 0.28 mm/pixel default). This parameter can only be used together with the `width` or `height` parameters (which provide an alternative mechanism to control the scale) if the implementation also supports subsetting, in which case those `width` and `height` parameters then control the subset of the map returned rather than the scale. If `scale-denominator` is omitted, the scale is implied from the dimensions of the returned map compared to its spatial subset area." + required: false + style: form + explode: false + schema: + type: number + - name: mm-per-pixel + in: query + description: "Display resolution of the target rendering device in millimeters per pixel. This parameter controls the relationship between the dimensions of the resulting map in pixels and the scale of the map. The display resolution is taken into account for applying symbology rules, for the `scale-denominator` parameter, and for the spatial subsetting using a `center`, `width` and `height` parameters." + required: false + style: form + explode: false + schema: + type: number + default: 0.28 + - name: orientation + in: query + description: "Orientation in degrees by which the content of the map is to be rotated around the center of the subset area as pivot point in a counter-clockwise direction, resulting in the viewing perspective being rotated by the same orientation in a clockwise direction." + required: false + style: form + explode: false + schema: + type: number + default: 0 + - name: crs-proj-method + in: query + description: Projection operation method for a custom projection CRS. + required: false + style: form + explode: false + schema: + type: string + - name: crs-proj-center + in: query + description: Projection center for a custom projection CRS corresponding to specific projection operation method parameters for latitude and longitude. + required: false + style: form + explode: false + schema: + type: string + - name: crs-proj-params + in: query + description: Operation method parameters for a custom projection CRS. + required: false + style: form + explode: false + schema: + type: string + - name: crs-datum + in: query + description: "Datum for a custom projection CRS, implying a particular ellipsoid." + required: false + style: form + explode: false + schema: + type: string + - name: f + in: query + description: "The format of the map response (e.g. png). Accepted values are 'png', 'jpg' or 'tiff' (GeoTIFF)." + required: false + style: form + explode: false + schema: + type: string + enum: + - png + - jpg + - tiff + responses: + "200": + $ref: "#/components/responses/Map" + "204": + $ref: "#/components/responses/EmptyMap" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/styles/{styleId}/map: + get: + tags: + - Maps + summary: Retrieve a map for a specified collection and style + operationId: .collection.style.getMap + parameters: + - name: bbox + in: query + description: |- + Only resources that have a geometry that intersects the bounding box are selected. The bounding box is provided as four or six numbers, depending on whether the coordinate reference system includes a vertical axis (elevation or depth): + * Lower left corner, coordinate axis 1 * Lower left corner, coordinate axis 2 * Minimum value, coordinate axis 3 (optional) * Upper right corner, coordinate axis 1 * Upper right corner, coordinate axis 2 * Maximum value, coordinate axis 3 (optional) + If the value consists of four numbers, the coordinate reference system is WGS84 longitude/latitude (http://www.opengis.net/def/crs/OGC/1.3/CRS84) unless a different coordinate reference system is specified in the parameter `bbox-crs`. + If the value consists of six numbers, the coordinate reference system is WGS 84 longitude/latitude/ellipsoidal height (http://www.opengis.net/def/crs/OGC/0/CRS84h) unless a different coordinate reference system is specified in a parameter `bbox-crs`. + For WGS84 longitude/latitude the values are in most cases the sequence of minimum longitude, minimum latitude, maximum longitude and maximum latitude. However, in cases where the box spans the antimeridian the first value (west-most box edge) is larger than the third value (east-most box edge). + If the vertical axis is included, the third and the sixth number are the bottom and the top of the 3-dimensional bounding box. + If a resource has multiple spatial geometry properties, it is the decision of the server whether only a single spatial geometry property is used to determine the extent or all relevant geometries. + required: false + style: form + explode: false + schema: + type: array + items: + type: number + - name: datetime + in: query + description: |- + Either a date-time or an interval. Date and time expressions adhere to RFC 3339, section 5.6. Intervals may be bounded or half-bounded (double-dots at start or end). Server implementations may or may not support times expressed using time offsets from UTC, but need to support UTC time with the notation ending with a Z. + Examples: + * A date-time: "2018-02-12T23:20:50Z" * A bounded interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" * Half-bounded intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z" + Only resources that have a temporal property that intersects the value of `datetime` are selected. + If a feature has multiple temporal properties, it is the decision of the server whether only a single temporal property is used to determine the extent or all relevant temporal properties. + required: false + style: form + explode: false + schema: + type: string + - name: collectionId + in: path + description: Local identifier of a collection + required: true + schema: + $ref: "#/components/schemas/all-collections" + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + - name: subset + in: query + description: | + Retrieve only part of the data by slicing or trimming along one or more axis + For trimming: {axisAbbrev}({low}:{high}) (preserves dimensionality) + For slicing: {axisAbbrev}({value}) (reduces dimensionality) + An asterisk (`*`) can be used instead of {low} or {high} to indicate the minimum/maximum value. + For a temporal dimension, a single asterisk can be used to indicate the high value. + Support for `*` is required for time, but optional for spatial and other dimensions. + required: false + style: form + explode: false + schema: + type: array + items: + type: string + - name: crs + in: query + description: reproject the output to the given crs + required: false + style: form + explode: true + schema: + type: string + - name: bbox-crs + in: query + description: crs for the specified bbox + required: false + style: form + explode: true + schema: + type: string + - name: subset-crs + in: query + description: crs for the specified subset + required: false + style: form + explode: true + schema: + type: string + - name: bgcolor + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the background color (default to 0x9C9C9C gray). If alpha is not specified, full opacity is assumed." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + - name: transparent + in: query + description: "Background transparency of map (defaults to `true` without a `bgcolor` specified, but to `false` when a `bgcolor` is used)." + required: false + style: form + explode: false + schema: + type: boolean + default: true + - name: void-color + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the void color for parts of the map outside of the valid area of the projection / CRS. If not specified, this defaults to the same as `bgcolor`." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + - name: void-transparent + in: query + description: Background transparency for parts of the map outside of the valid areas of the CRS / projection (defaults to the same as `transparent` if not specified). + required: false + style: form + explode: false + schema: + type: boolean + default: true + - name: width + in: query + description: "Width of the map in pixels. If omitted and `height` is specified, defaults to the width maintaining a 1:1 aspect ratio. If both `width` and `height` are omitted, the server will select default dimensions. When used together with the `center` and/or `scale-denominator` parameter, `width` takes on a subsetting role rather than scaling (resampling), defining the horizontal portion of the map to subset based on the scale (native scale, or specified by `scale-denominator`) and display resolution (0.28 mm/pixel, or specified by `mm-per-pixel`)." + required: false + style: form + explode: false + schema: + type: integer + - name: height + in: query + description: "Height of the map in pixels. If omitted and `width` is specified, defaults to the height maintaining a 1:1 aspect ratio. If both `width` and `height` are omitted, the server will select default dimensions. When used together with the `center` and/or `scale-denominator` parameter, `height` takes on a subsetting role rather than scaling (resampling), defining the vertical portion of the map to subset based on the scale (native scale, or specified by `scale-denominator`) and display resolution (0.28 mm/pixel, or specified by `mm-per-pixel`)." + required: false + style: form + explode: false + schema: + type: integer + - name: center + in: query + description: "Coordinates of center point for subsetting, in conjunction with the `width` and/or `height` parameters, taking into consideration the scale and display resolution of the map. The center coordinates are comma-separated and interpreted as [ogc:CRS84], unless the `center-crs` parameter specifies otherwise." + required: false + style: form + explode: false + schema: + maxItems: 2 + minItems: 2 + type: array + items: + type: number + - name: center-crs + in: query + description: CRS for the specified center point + required: false + style: form + explode: true + schema: + type: string + - name: scale-denominator + in: query + description: "Scale denominator of the map specifying to how many units in the real world one of the same unit on the map corresponds, as printed or displayed, taking into account the display resolution (`mm-per-pixel` or 0.28 mm/pixel default). This parameter can only be used together with the `width` or `height` parameters (which provide an alternative mechanism to control the scale) if the implementation also supports subsetting, in which case those `width` and `height` parameters then control the subset of the map returned rather than the scale. If `scale-denominator` is omitted, the scale is implied from the dimensions of the returned map compared to its spatial subset area." + required: false + style: form + explode: false + schema: + type: number + - name: mm-per-pixel + in: query + description: "Display resolution of the target rendering device in millimeters per pixel. This parameter controls the relationship between the dimensions of the resulting map in pixels and the scale of the map. The display resolution is taken into account for applying symbology rules, for the `scale-denominator` parameter, and for the spatial subsetting using a `center`, `width` and `height` parameters." + required: false + style: form + explode: false + schema: + type: number + default: 0.28 + - name: orientation + in: query + description: "Orientation in degrees by which the content of the map is to be rotated around the center of the subset area as pivot point in a counter-clockwise direction, resulting in the viewing perspective being rotated by the same orientation in a clockwise direction." + required: false + style: form + explode: false + schema: + type: number + default: 0 + - name: crs-proj-method + in: query + description: Projection operation method for a custom projection CRS. + required: false + style: form + explode: false + schema: + type: string + - name: crs-proj-center + in: query + description: Projection center for a custom projection CRS corresponding to specific projection operation method parameters for latitude and longitude. + required: false + style: form + explode: false + schema: + type: string + - name: crs-proj-params + in: query + description: Operation method parameters for a custom projection CRS. + required: false + style: form + explode: false + schema: + type: string + - name: crs-datum + in: query + description: "Datum for a custom projection CRS, implying a particular ellipsoid." + required: false + style: form + explode: false + schema: + type: string + - name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + type: string + - name: f + in: query + description: "The format of the map response (e.g. png). Accepted values are 'png', 'jpg' or 'tiff' (GeoTIFF)." + required: false + style: form + explode: false + schema: + type: string + enum: + - png + - jpg + - tiff + responses: + "200": + $ref: "#/components/responses/Map" + "204": + $ref: "#/components/responses/EmptyMap" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /projectionsAndDatums: + get: + tags: + - Custom Projection CRS + summary: Retrieve the list of custom CRS projection operation methods (including their associated parameters) and datums supported by this API. + operationId: getCustomCRSProjections + parameters: + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + description: The list of custom CRS projection operation methods (including their associated parameters) and datums supported by this API. + content: + application/json: + schema: + $ref: "#/components/schemas/Custom CRS projections and datums" + text/html: + schema: + type: string + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /tileMatrixSets: + get: + tags: + - Tiling Schemes + summary: Retrieve the list of available tiling schemes (tile matrix sets) + operationId: getTileMatrixSetsList + parameters: + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileMatrixSetsList" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /tileMatrixSets/{tileMatrixSetId}: + get: + tags: + - Tiling Schemes + summary: Retrieve the definition of the specified tiling scheme (tile matrix set) + operationId: getTileMatrixSet + parameters: + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileMatrixSet" + "404": + description: The requested tile matrix set id was not found + content: + application/json: + schema: + $ref: "#/components/schemas/exception" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /map/tiles: + get: + tags: + - Map Tiles + summary: Retrieve the list of all default map tilesets for the whole dataset + operationId: .dataset.map.getTileSetsList + parameters: + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileSetsList" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /map/tiles/{tileMatrixSetId}: + get: + tags: + - Map Tiles + summary: Retrieve a default map tileset of the whole dataset for the specified tiling scheme (tile matrix set) + operationId: .dataset.map.getTileSet + parameters: + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileSet" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /map/tiles/{tileMatrixSetId}/{tileMatrix}/{tileRow}/{tileCol}: + get: + tags: + - Map Tiles + summary: Retrieve a default map tile of the whole dataset + operationId: .dataset.map.getTile + parameters: + - name: tileMatrix + in: path + description: |- + Identifier selecting one of the scales defined in the TileMatrixSet and representing the scaleDenominator the tile. For example, + Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15. + required: true + schema: + type: string + example: "5" + - name: tileRow + in: path + description: "Row index of the tile on the selected TileMatrix. It cannot exceed the MatrixWidth-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 10 + - name: tileCol + in: path + description: "Column index of the tile on the selected TileMatrix. It cannot exceed the MatrixHeight-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 15 + - name: datetime + in: query + description: |- + Either a date-time or an interval. Date and time expressions adhere to RFC 3339, section 5.6. Intervals may be bounded or half-bounded (double-dots at start or end). Server implementations may or may not support times expressed using time offsets from UTC, but need to support UTC time with the notation ending with a Z. + Examples: + * A date-time: "2018-02-12T23:20:50Z" * A bounded interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" * Half-bounded intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z" + Only resources that have a temporal property that intersects the value of `datetime` are selected. + If a feature has multiple temporal properties, it is the decision of the server whether only a single temporal property is used to determine the extent or all relevant temporal properties. + required: false + style: form + explode: false + schema: + type: string + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + - name: subset + in: query + description: | + Retrieve only part of the data by slicing or trimming along one or more axis + For trimming: {axisAbbrev}({low}:{high}) (preserves dimensionality) + For slicing: {axisAbbrev}({value}) (reduces dimensionality) + An asterisk (`*`) can be used instead of {low} or {high} to indicate the minimum/maximum value. + For a temporal dimension, a single asterisk can be used to indicate the high value. + Support for `*` is required for time, but optional for spatial and other dimensions. + required: false + style: form + explode: false + schema: + type: array + items: + type: string + - name: crs + in: query + description: reproject the output to the given crs + required: false + style: form + explode: true + schema: + type: string + - name: subset-crs + in: query + description: crs for the specified subset + required: false + style: form + explode: true + schema: + type: string + - name: bgcolor + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the background color (default to 0x9C9C9C gray). If alpha is not specified, full opacity is assumed." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + - name: transparent + in: query + description: "Background transparency of map (defaults to `true` without a `bgcolor` specified, but to `false` when a `bgcolor` is used)." + required: false + style: form + explode: false + schema: + type: boolean + default: true + - name: void-color + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the void color for parts of the map outside of the valid area of the projection / CRS. If not specified, this defaults to the same as `bgcolor`." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + - name: void-transparent + in: query + description: Background transparency for parts of the map outside of the valid areas of the CRS / projection (defaults to the same as `transparent` if not specified). + required: false + style: form + explode: false + schema: + type: boolean + default: true + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the map tile response (e.g. png). Accepted values are 'png', 'jpg' or 'tiff' (GeoTIFF)." + required: false + style: form + explode: false + schema: + type: string + enum: + - png + - jpg + - tiff + responses: + "200": + $ref: "#/components/responses/MapTile" + "204": + $ref: "#/components/responses/EmptyTile" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /styles/{styleId}/map/tiles: + get: + tags: + - Map Tiles + summary: Retrieve the list of styled map tilesets for the whole dataset + operationId: .dataset.style.map.getTileSetsList + parameters: + - name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + $ref: "#/components/schemas/styles" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileSetsList" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /styles/{styleId}/map/tiles/{tileMatrixSetId}: + get: + tags: + - Map Tiles + summary: Retrieve a styled map tileset of the whole dataset for the specified tiling scheme (tile matrix set) + operationId: .dataset.style.map.getTileSet + parameters: + - name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + $ref: "#/components/schemas/styles" + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileSet" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /styles/{styleId}/map/tiles/{tileMatrixSetId}/{tileMatrix}/{tileRow}/{tileCol}: + get: + tags: + - Map Tiles + summary: Retrieve a styled map tiles + operationId: .dataset.style.map.getTile + parameters: + - name: tileMatrix + in: path + description: |- + Identifier selecting one of the scales defined in the TileMatrixSet and representing the scaleDenominator the tile. For example, + Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15. + required: true + schema: + type: string + example: "5" + - name: tileRow + in: path + description: "Row index of the tile on the selected TileMatrix. It cannot exceed the MatrixWidth-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 10 + - name: tileCol + in: path + description: "Column index of the tile on the selected TileMatrix. It cannot exceed the MatrixHeight-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 15 + - name: datetime + in: query + description: |- + Either a date-time or an interval. Date and time expressions adhere to RFC 3339, section 5.6. Intervals may be bounded or half-bounded (double-dots at start or end). Server implementations may or may not support times expressed using time offsets from UTC, but need to support UTC time with the notation ending with a Z. + Examples: + * A date-time: "2018-02-12T23:20:50Z" * A bounded interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" * Half-bounded intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z" + Only resources that have a temporal property that intersects the value of `datetime` are selected. + If a feature has multiple temporal properties, it is the decision of the server whether only a single temporal property is used to determine the extent or all relevant temporal properties. + required: false + style: form + explode: false + schema: + type: string + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + - name: subset + in: query + description: | + Retrieve only part of the data by slicing or trimming along one or more axis + For trimming: {axisAbbrev}({low}:{high}) (preserves dimensionality) + For slicing: {axisAbbrev}({value}) (reduces dimensionality) + An asterisk (`*`) can be used instead of {low} or {high} to indicate the minimum/maximum value. + For a temporal dimension, a single asterisk can be used to indicate the high value. + Support for `*` is required for time, but optional for spatial and other dimensions. + required: false + style: form + explode: false + schema: + type: array + items: + type: string + - name: crs + in: query + description: reproject the output to the given crs + required: false + style: form + explode: true + schema: + type: string + - name: subset-crs + in: query + description: crs for the specified subset + required: false + style: form + explode: true + schema: + type: string + - name: bgcolor + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the background color (default to 0x9C9C9C gray). If alpha is not specified, full opacity is assumed." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + - name: transparent + in: query + description: "Background transparency of map (defaults to `true` without a `bgcolor` specified, but to `false` when a `bgcolor` is used)." + required: false + style: form + explode: false + schema: + type: boolean + default: true + - name: void-color + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the void color for parts of the map outside of the valid area of the projection / CRS. If not specified, this defaults to the same as `bgcolor`." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + - name: void-transparent + in: query + description: Background transparency for parts of the map outside of the valid areas of the CRS / projection (defaults to the same as `transparent` if not specified). + required: false + style: form + explode: false + schema: + type: boolean + default: true + - name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + $ref: "#/components/schemas/styles" + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the map tile response (e.g. png). Accepted values are 'png', 'jpg' or 'tiff' (GeoTIFF)." + required: false + style: form + explode: false + schema: + type: string + enum: + - png + - jpg + - tiff + responses: + "200": + $ref: "#/components/responses/MapTile" + "204": + $ref: "#/components/responses/EmptyTile" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/map/tiles: + get: + tags: + - Map Tiles + summary: Retrieve a list of all map tilesets for specified collection. + operationId: .collection.map.getTileSetsList + parameters: + - name: collectionId + in: path + description: Local identifier of a collection + required: true + schema: + $ref: "#/components/schemas/all-collections" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileSetsList" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/map/tiles/{tileMatrixSetId}: + get: + tags: + - Map Tiles + summary: Retrieve a map tile set metadata for the specified collection and tiling scheme (tile matrix set) + operationId: .collection.map.getTileSet + parameters: + - name: collectionId + in: path + description: Local identifier of a collection + required: true + schema: + $ref: "#/components/schemas/all-collections" + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileSet" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/map/tiles/{tileMatrixSetId}/{tileMatrix}/{tileRow}/{tileCol}: + get: + tags: + - Map Tiles + summary: Retrieve a map tile from the specified collection + operationId: .collection.map.getTile + parameters: + - name: tileMatrix + in: path + description: |- + Identifier selecting one of the scales defined in the TileMatrixSet and representing the scaleDenominator the tile. For example, + Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15. + required: true + schema: + type: string + example: "5" + - name: tileRow + in: path + description: "Row index of the tile on the selected TileMatrix. It cannot exceed the MatrixWidth-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 10 + - name: tileCol + in: path + description: "Column index of the tile on the selected TileMatrix. It cannot exceed the MatrixHeight-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 15 + - name: datetime + in: query + description: |- + Either a date-time or an interval. Date and time expressions adhere to RFC 3339, section 5.6. Intervals may be bounded or half-bounded (double-dots at start or end). Server implementations may or may not support times expressed using time offsets from UTC, but need to support UTC time with the notation ending with a Z. + Examples: + * A date-time: "2018-02-12T23:20:50Z" * A bounded interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" * Half-bounded intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z" + Only resources that have a temporal property that intersects the value of `datetime` are selected. + If a feature has multiple temporal properties, it is the decision of the server whether only a single temporal property is used to determine the extent or all relevant temporal properties. + required: false + style: form + explode: false + schema: + type: string + - name: collectionId + in: path + description: Local identifier of a collection + required: true + schema: + $ref: "#/components/schemas/all-collections" + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + - name: subset + in: query + description: | + Retrieve only part of the data by slicing or trimming along one or more axis + For trimming: {axisAbbrev}({low}:{high}) (preserves dimensionality) + For slicing: {axisAbbrev}({value}) (reduces dimensionality) + An asterisk (`*`) can be used instead of {low} or {high} to indicate the minimum/maximum value. + For a temporal dimension, a single asterisk can be used to indicate the high value. + Support for `*` is required for time, but optional for spatial and other dimensions. + required: false + style: form + explode: false + schema: + type: array + items: + type: string + - name: crs + in: query + description: reproject the output to the given crs + required: false + style: form + explode: true + schema: + type: string + - name: subset-crs + in: query + description: crs for the specified subset + required: false + style: form + explode: true + schema: + type: string + - name: bgcolor + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the background color (default to 0x9C9C9C gray). If alpha is not specified, full opacity is assumed." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + - name: transparent + in: query + description: "Background transparency of map (defaults to `true` without a `bgcolor` specified, but to `false` when a `bgcolor` is used)." + required: false + style: form + explode: false + schema: + type: boolean + default: true + - name: void-color + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the void color for parts of the map outside of the valid area of the projection / CRS. If not specified, this defaults to the same as `bgcolor`." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + - name: void-transparent + in: query + description: Background transparency for parts of the map outside of the valid areas of the CRS / projection (defaults to the same as `transparent` if not specified). + required: false + style: form + explode: false + schema: + type: boolean + default: true + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the map tile response (e.g. png). Accepted values are 'png', 'jpg' or 'tiff' (GeoTIFF)." + required: false + style: form + explode: false + schema: + type: string + enum: + - png + - jpg + - tiff + responses: + "200": + $ref: "#/components/responses/MapTile" + "204": + $ref: "#/components/responses/EmptyTile" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/styles/{styleId}/map/tiles: + get: + tags: + - Map Tiles + summary: Retrieve a list of styled map tilesets for the specified collection + operationId: .collection.style.map.getTileSetsList + parameters: + - name: collectionId + in: path + description: Local identifier of a collection + required: true + schema: + $ref: "#/components/schemas/all-collections" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + - name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + type: string + responses: + "200": + $ref: "#/components/responses/TileSetsList" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/styles/{styleId}/map/tiles/{tileMatrixSetId}: + get: + tags: + - Map Tiles + summary: "Retrieve the map tileset metadata for the specified collection, style and tiling scheme (tile matrix set)." + operationId: .collection.style.map.getTileSet + parameters: + - name: collectionId + in: path + description: Local identifier of a collection + required: true + schema: + $ref: "#/components/schemas/all-collections" + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + - name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + type: string + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileSet" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/styles/{styleId}/map/tiles/{tileMatrixSetId}/{tileMatrix}/{tileRow}/{tileCol}: + get: + tags: + - Map Tiles + summary: Retrieve a map tile for a specified collection and style + operationId: .collection.style.map.getTile + parameters: + - name: tileMatrix + in: path + description: |- + Identifier selecting one of the scales defined in the TileMatrixSet and representing the scaleDenominator the tile. For example, + Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15. + required: true + schema: + type: string + example: "5" + - name: tileRow + in: path + description: "Row index of the tile on the selected TileMatrix. It cannot exceed the MatrixWidth-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 10 + - name: tileCol + in: path + description: "Column index of the tile on the selected TileMatrix. It cannot exceed the MatrixHeight-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 15 + - name: datetime + in: query + description: |- + Either a date-time or an interval. Date and time expressions adhere to RFC 3339, section 5.6. Intervals may be bounded or half-bounded (double-dots at start or end). Server implementations may or may not support times expressed using time offsets from UTC, but need to support UTC time with the notation ending with a Z. + Examples: + * A date-time: "2018-02-12T23:20:50Z" * A bounded interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" * Half-bounded intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z" + Only resources that have a temporal property that intersects the value of `datetime` are selected. + If a feature has multiple temporal properties, it is the decision of the server whether only a single temporal property is used to determine the extent or all relevant temporal properties. + required: false + style: form + explode: false + schema: + type: string + - name: collectionId + in: path + description: Local identifier of a collection + required: true + schema: + $ref: "#/components/schemas/all-collections" + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + - name: subset + in: query + description: | + Retrieve only part of the data by slicing or trimming along one or more axis + For trimming: {axisAbbrev}({low}:{high}) (preserves dimensionality) + For slicing: {axisAbbrev}({value}) (reduces dimensionality) + An asterisk (`*`) can be used instead of {low} or {high} to indicate the minimum/maximum value. + For a temporal dimension, a single asterisk can be used to indicate the high value. + Support for `*` is required for time, but optional for spatial and other dimensions. + required: false + style: form + explode: false + schema: + type: array + items: + type: string + - name: crs + in: query + description: reproject the output to the given crs + required: false + style: form + explode: true + schema: + type: string + - name: subset-crs + in: query + description: crs for the specified subset + required: false + style: form + explode: true + schema: + type: string + - name: bgcolor + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the background color (default to 0x9C9C9C gray). If alpha is not specified, full opacity is assumed." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + - name: transparent + in: query + description: "Background transparency of map (defaults to `true` without a `bgcolor` specified, but to `false` when a `bgcolor` is used)." + required: false + style: form + explode: false + schema: + type: boolean + default: true + - name: void-color + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the void color for parts of the map outside of the valid area of the projection / CRS. If not specified, this defaults to the same as `bgcolor`." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + - name: void-transparent + in: query + description: Background transparency for parts of the map outside of the valid areas of the CRS / projection (defaults to the same as `transparent` if not specified). + required: false + style: form + explode: false + schema: + type: boolean + default: true + - name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + type: string + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the map tile response (e.g. png). Accepted values are 'png', 'jpg' or 'tiff' (GeoTIFF)." + required: false + style: form + explode: false + schema: + type: string + enum: + - png + - jpg + - tiff + responses: + "200": + $ref: "#/components/responses/MapTile" + "204": + $ref: "#/components/responses/EmptyTile" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" +components: + schemas: + confClasses: + required: + - conformsTo + type: object + properties: + conformsTo: + type: array + items: + type: string + link: + required: + - href + - rel + type: object + properties: + href: + type: string + description: Supplies the URI to a remote resource (or resource fragment). + example: http://data.example.com/buildings/123 + rel: + type: string + description: The type or semantics of the relation. + example: alternate + type: + type: string + description: A hint indicating what the media type of the result of dereferencing the link should be. + example: application/geo+json + templated: + type: boolean + description: This flag set to true if the link is a URL template. + varBase: + type: string + description: A base path to retrieve semantic information about the variables used in URL template. + example: /ogcapi/vars/ + hreflang: + type: string + description: A hint indicating what the language of the result of dereferencing the link should be. + example: en + title: + type: string + description: Used to label the destination of a link such that it can be used as a human-readable identifier. + example: "Trierer Strasse 70, 53115 Bonn" + length: + type: integer + landingPage: + required: + - links + type: object + properties: + title: + title: The title of the API. + type: string + description: "While a title is not required, implementors are strongly advised to include one." + example: Buildings in Bonn + description: + type: string + example: Access to data about buildings in the city of Bonn via a Web API that conforms to the OGC API Common specification. + attribution: + title: attribution for the API + type: string + description: "The `attribution` should be short and intended for presentation to a user, for example, in a corner of a map. Parts of the text can be links to other resources if additional information is needed. The string can include HTML markup." + links: + type: array + items: + $ref: "#/components/schemas/link" + exception: + title: Exception Schema + required: + - type + type: object + properties: + type: + type: string + title: + type: string + status: + type: integer + detail: + type: string + instance: + type: string + description: JSON schema for exceptions based on RFC 7807 + collections: + required: + - collections + - links + type: object + properties: + links: + type: array + items: + $ref: "#/components/schemas/link" + timeStamp: + type: string + format: date-time + numberMatched: + $ref: "#/components/schemas/numberMatched" + numberReturned: + $ref: "#/components/schemas/numberReturned" + collections: + type: array + items: + $ref: "#/components/schemas/collectionDesc" + collectionDesc: + required: + - id + - links + type: object + properties: + id: + type: string + description: "identifier of the collection used, for example, in URIs" + example: dem + title: + type: string + description: human readable title of the collection + example: Digital Elevation Model + description: + type: string + description: a description of the data in the collection + example: A Digital Elevation Model. + attribution: + title: attribution for the collection + type: string + links: + type: array + example: + - href: http://data.example.org/collections/dem?f=json + rel: self + type: application/json + title: Digital Elevation Model + - href: http://data.example.org/collections/dem?f=html + rel: alternate + type: application/json + title: Digital Elevation Model + - href: http://data.example.org/collections/dem/coverage + rel: coverage + type: image/tiff; application=geotiff + title: Digital Elevation Model + - href: http://data.example.org/collections/dem/coverage/domainset + rel: domainset + type: application/json + title: Digital Elevation Model + - href: http://data.example.org/collections/dem/coverage/rangetype + rel: rangetype + type: application/json + title: Digital Elevation Model + - href: http://data.example.org/collections/dem/coverage/metadata + rel: metadata + type: application/json + title: Digital Elevation Model + items: + $ref: "#/components/schemas/link" + extent: + $ref: "#/components/schemas/extent-uad" + itemType: + type: string + description: "indicator about the type of the items in the collection if the collection has an accessible /collections/{collectionId}/items endpoint" + default: unknown + crs: + type: array + description: the list of coordinate reference systems supported by the API; the first item is the default coordinate reference system + example: + - http://www.opengis.net/def/crs/OGC/1.3/CRS84 + - http://www.opengis.net/def/crs/EPSG/0/4326 + items: + type: string + default: + - http://www.opengis.net/def/crs/OGC/1.3/CRS84 + storageCrs: + type: string + description: "the native coordinate reference system (i.e., the most efficient CRS in which to request the data, possibly how the data is stored on the server); this is the default output coordinate reference system for Maps and Coverages" + example: http://www.opengis.net/def/crs/OGC/1.3/CRS84 + default: http://www.opengis.net/def/crs/OGC/1.3/CRS84 + dataType: + allOf: + - description: Type of data represented in the collection + - $ref: "#/components/schemas/dataType" + geometryDimension: + maximum: 3 + minimum: 0 + type: integer + description: "The geometry dimension of the features shown in this layer (0: points, 1: curves, 2: surfaces, 3: solids), unspecified: mixed or unknown" + minScaleDenominator: + type: number + description: Minimum scale denominator for usage of the collection + maxScaleDenominator: + type: number + description: Maximum scale denominator for usage of the collection + minCellSize: + type: number + description: Minimum cell size for usage of the collection + maxCellSize: + type: number + description: Maximum cell size for usage of the collection + extent: + type: object + properties: + spatial: + $ref: "#/components/schemas/extent_spatial" + temporal: + $ref: "#/components/schemas/extent_temporal" + description: |- + The extent of the data in the collection. In the Core only spatial and temporal + extents are specified. Extensions may add additional members to represent other + extents, for example, thermal or pressure ranges. + + The first item in the array describes the overall extent of + the data. All subsequent items describe more precise extents, + e.g., to identify clusters of data. + Clients only interested in the overall extent will only need to + access the first item in each array. + extent-uad: + title: Extent with Uniform Additional Dimensions Schema + description: |- + The extent module only addresses spatial and temporal extents. This module extends extent by specifying how + intervals and crs properties can be used to specify additional geometries. + allOf: + - $ref: "#/components/schemas/extent" + - type: object + additionalProperties: + type: object + properties: + interval: + minItems: 1 + type: array + description: |- + One or more intervals that describe the extent for this dimension of the dataset. + The value `null` is supported and indicates an unbounded or half-bounded interval. + The first interval describes the overall extent of the data for this dimension. + All subsequent intervals describe more precise intervals, e.g., to identify clusters of data. + Clients only interested in the overall extent will only need + to access the first item (a pair of lower and upper bound values). + items: + maxItems: 2 + minItems: 2 + type: array + description: |- + Lower and upper bound values of the interval. The values + are in the coordinate reference system specified in `crs`, `trs` or `vrs`. + example: + - 2011-11-11T12:22:11Z + - 2011-11-11T08:22:11-04:00 + - 32.5 + - null + items: + oneOf: + - type: string + nullable: true + - type: number + trs: + type: string + description: temporal coordinate reference system (e.g. as defined by Features for 'temporal') + vrs: + type: string + description: vertical coordinate reference system (e.g. as defined in EDR for 'vertical') + grid: + type: object + properties: + coordinates: + minItems: 1 + type: array + description: |- + List of coordinates along the temporal dimension for which data organized as an irregular grid in the collection is available + (e.g., 2, 10, 80, 100). + example: + - 2 + - 10 + - 80 + - 100 + items: + oneOf: + - type: string + nullable: true + - type: number + cellsCount: + type: integer + description: |- + Number of samples available along the dimension for data organized as a regular grid. + For values representing the whole area of contiguous cells spanning _resolution_ units along the dimension, this will be (_upperBound_ - _lowerBound_) / _resolution_. + For values representing infinitely small point cells spaced by _resolution_ units along the dimension, this will be (_upperBound_ - _lowerBound_) / _resolution_ + 1. + example: 50 + resolution: + description: Resolution of regularly gridded data along the dimension in the collection + example: + - PT1H + - 0.0006866455078 + oneOf: + - type: string + nullable: true + - type: number + description: Provides information about the limited availability of data within the collection organized as a grid (regular or irregular) along the dimension. + definition: + type: string + description: A URI to the definition of the measured or observed property corresponding to this dimension. + format: uri + unit: + type: string + description: The unit of measure in which the interval and/or grid values are expressed. + unitLang: + type: string + description: The language (or vocabulary) in which the unit is expressed (defaults to "UCUM" if not specified). + default: UCUM + description: The domain intervals for any additional dimensions of the extent (envelope) beyond those described in temporal and spatial. + oneOf: + - required: + - definition + - interval + - required: + - interval + - trs + - required: + - interval + - vrs + crs: + title: CRS + oneOf: + - type: string + description: Simplification of the object into a url if the other properties are not present + - type: object + oneOf: + - required: + - uri + properties: + uri: + type: string + description: Reference to one coordinate reference system (CRS) + format: uri + - required: + - wkt + properties: + wkt: + allOf: + - description: An object defining the CRS using the JSON encoding for Well-known text representation of coordinate reference systems 2.0 + - type: object + - required: + - referenceSystem + properties: + referenceSystem: + type: object + description: A reference system data structure as defined in the MD_ReferenceSystem of the ISO 19115 + dataType: + anyOf: + - type: string + - type: string + enum: + - map + - vector + - coverage + timeStamp: + type: string + description: This property indicates the time and date when the response was generated using RFC 3339 notation. + format: date-time + example: 2017-08-17T08:05:32Z + numberReturned: + minimum: 0 + type: integer + description: |- + The number of elements in the response. + A server may omit this information, if the information about the + number of elements is not known or difficult to compute. + If the value is provided, the value shall be identical to the number + of elements in the response. + example: 10 + numberMatched: + minimum: 0 + type: integer + description: The number of elements in the response that match the selection parameters like `bbox`. + example: 127 + tileSet: + title: Tile Set Metadata + required: + - crs + - dataType + - links + type: object + properties: + title: + type: string + description: A title for this tileset + description: + type: string + description: Brief narrative description of this tile set + dataType: + allOf: + - description: Type of data represented in the tileset + - $ref: "#/components/schemas/dataType" + crs: + allOf: + - description: Coordinate Reference System (CRS) + - $ref: "#/components/schemas/crs" + tileMatrixSetURI: + type: string + description: Reference to a Tile Matrix Set on an offical source for Tile Matrix Sets such as the OGC NA definition server (http://www.opengis.net/def/tms/). Required if the tile matrix set is registered on an open official source. + format: uri + links: + type: array + description: "Links to related resources. Possible link 'rel' values are: 'http://www.opengis.net/def/rel/ogc/1.0/dataset' for a URL pointing to the dataset, 'item' for a URL template to get a tile; 'alternate' for a URL pointing to another representation of the TileSetMetadata (e.g a TileJSON file); 'http://www.opengis.net/def/rel/ogc/1.0/tiling-scheme' for a definition of the TileMatrixSet; 'http://www.opengis.net/def/rel/ogc/1.0/geodata' for pointing to a single collection (if the tileset represents a single collection)" + items: + $ref: "#/components/schemas/link" + tileMatrixSetLimits: + type: array + description: "Limits for the TileRow and TileCol values for each TileMatrix in the tileMatrixSet. If missing, there are no limits other that the ones imposed by the TileMatrixSet. If present the TileMatrices listed are limited and the rest not available at all" + items: + $ref: "#/components/schemas/tileMatrixLimits" + epoch: + type: number + description: Epoch of the Coordinate Reference System (CRS) + layers: + minItems: 1 + type: array + items: + $ref: "#/components/schemas/tileSet_layers" + boundingBox: + allOf: + - description: "Minimum bounding rectangle surrounding the tile matrix set, in the supported CRS" + - $ref: "#/components/schemas/2DBoundingBox" + centerPoint: + allOf: + - description: Location of a tile that nicely represents the tileset. Implementations may use this center value to set the default location or to present a representative tile in a user interface + - required: + - coordinates + type: object + properties: + coordinates: + maxItems: 2 + minItems: 2 + type: array + items: + type: number + crs: + allOf: + - description: Coordinate Reference System (CRS) of the coordinates + - $ref: "#/components/schemas/crs" + tileMatrix: + type: string + description: TileMatrix identifier associated with the scaleDenominator + scaleDenominator: + type: number + description: Scale denominator of the tile matrix selected + cellSize: + type: number + description: Cell size of the tile matrix selected + style: + allOf: + - description: Style involving all layers used to generate the tileset + - required: + - id + type: object + properties: + id: + type: string + description: An identifier for this style. Implementation of 'identifier' + title: + type: string + description: A title for this style + description: + type: string + description: Brief narrative description of this style + keywords: + type: array + description: keywords about this style + items: + type: string + links: + minItems: 1 + type: array + description: "Links to style related resources. Possible link 'rel' values are: 'style' for a URL pointing to the style description, 'styleSpec' for a URL pointing to the specification or standard used to define the style." + items: + $ref: "#/components/schemas/link" + attribution: + type: string + description: Short reference to recognize the author or provider + license: + type: string + description: License applicable to the tiles + accessConstraints: + type: string + description: Restrictions on the availability of the Tile Set that the user needs to be aware of before using or redistributing the Tile Set + default: unclassified + enum: + - unclassified + - restricted + - confidential + - secret + - topSecret + keywords: + type: array + description: keywords about this tileset + items: + type: string + version: + type: string + description: Version of the Tile Set. Changes if the data behind the tiles has been changed + created: + allOf: + - description: When the Tile Set was first produced + - $ref: "#/components/schemas/timeStamp" + updated: + allOf: + - description: Last Tile Set change/revision + - $ref: "#/components/schemas/timeStamp" + pointOfContact: + type: string + description: Useful information to contact the authors or custodians for the Tile Set + mediaTypes: + type: array + description: Media types available for the tiles + items: + type: string + description: "A resource describing a tileset based on the OGC TileSet Metadata Standard. At least one of the 'TileMatrixSet', or a link with 'rel' http://www.opengis.net/def/rel/ogc/1.0/tiling-scheme" + tileSet-item: + title: Tile Set Metadata item + required: + - crs + - dataType + - links + type: object + properties: + title: + type: string + description: A title for this tileset + dataType: + allOf: + - description: Type of data represented in the tileset + - $ref: "#/components/schemas/dataType" + crs: + allOf: + - description: Coordinate Reference System (CRS) + - $ref: "#/components/schemas/crs" + tileMatrixSetURI: + type: string + description: Reference to a Tile Matrix Set on an offical source for Tile Matrix Sets such as the OGC NA definition server (http://www.opengis.net/def/tms/). Required if the tile matrix set is registered on an open official source. + format: uri + links: + type: array + description: Links to related resources. A 'self' link to the tileset as well as a 'http://www.opengis.net/def/rel/ogc/1.0/tiling-scheme' link to a definition of the TileMatrixSet are required. + items: + $ref: "#/components/schemas/link" + description: A minimal tileset element for use within a list of tilesets linking to full description of those tilesets. + tileMatrixSet: + title: Tile Matrix Set Definition + required: + - crs + - tileMatrices + type: object + properties: + title: + type: string + description: "Title of this tile matrix set, normally used for display to a human" + description: + type: string + description: "Brief narrative description of this tile matrix set, normally available for display to a human" + keywords: + type: array + description: Unordered list of one or more commonly used or formalized word(s) or phrase(s) used to describe this tile matrix set + items: + type: string + id: + type: string + description: Tile matrix set identifier. Implementation of 'identifier' + uri: + type: string + description: Reference to an official source for this tileMatrixSet + format: uri + orderedAxes: + minItems: 1 + type: array + items: + type: string + crs: + allOf: + - description: Coordinate Reference System (CRS) + - $ref: "#/components/schemas/crs" + wellKnownScaleSet: + type: string + description: Reference to a well-known scale set + format: uri + boundingBox: + allOf: + - description: "Minimum bounding rectangle surrounding the tile matrix set, in the supported CRS" + - $ref: "#/components/schemas/2DBoundingBox" + tileMatrices: + type: array + description: Describes scale levels and its tile matrices + items: + $ref: "#/components/schemas/tileMatrixSet_tileMatrices" + description: "A definition of a tile matrix set following the Tile Matrix Set standard. For tileset metadata, such a description (in `tileMatrixSet` property) is only required for offline use, as an alternative to a link with a `http://www.opengis.net/def/rel/ogc/1.0/tiling-scheme` relation type." + tileMatrixSet-item: + title: Tile Matrix Set Item + required: + - links + type: object + properties: + id: + type: string + description: "Optional local tile matrix set identifier, e.g. for use as unspecified `{tileMatrixSetId}` parameter. Implementation of 'identifier'" + title: + type: string + description: "Title of this tile matrix set, normally used for display to a human" + uri: + type: string + description: Reference to an official source for this tileMatrixSet + format: uri + crs: + allOf: + - description: Coordinate Reference System (CRS) + - $ref: "#/components/schemas/crs" + links: + type: array + description: Links to related resources. A 'self' link to the tile matrix set definition is required. + items: + $ref: "#/components/schemas/link" + description: A minimal tile matrix set element for use within a list of tile matrix sets linking to a full definition. + tileMatrixLimits: + title: TileMatrixLimits + required: + - maxTileCol + - maxTileRow + - minTileCol + - minTileRow + - tileMatrix + type: object + properties: + tileMatrix: + type: string + minTileRow: + minimum: 0 + type: integer + maxTileRow: + minimum: 0 + type: integer + minTileCol: + minimum: 0 + type: integer + maxTileCol: + minimum: 0 + type: integer + description: "The limits for an individual tile matrix of a TileSet's TileMatrixSet, as defined in the OGC 2D TileMatrixSet and TileSet Metadata Standard" + "2DPoint": + maxItems: 2 + minItems: 2 + type: array + description: A 2D Point in the CRS indicated elsewhere + items: + type: number + "2DBoundingBox": + required: + - lowerLeft + - upperRight + type: object + properties: + lowerLeft: + $ref: "#/components/schemas/2DPoint" + upperRight: + $ref: "#/components/schemas/2DPoint" + crs: + $ref: "#/components/schemas/crs" + orderedAxes: + maxItems: 2 + minItems: 2 + type: array + items: + type: string + description: Minimum bounding rectangle surrounding a 2D resource in the CRS indicated elsewhere + enumeration: + required: + - enum + - type + type: object + properties: + type: + type: string + enum: + - enum + enum: + type: array + items: + type: string + all-collections: + type: string + enum: + - blueMarble + - NaturalEarth:raster:HYP_HR_SR_OB_DR + - NaturalEarth:cultural:ne_10m_admin_0_countries + - NaturalEarth:physical:bathymetry + - SRTM_ViewFinderPanorama + - HRDEM-Ottawa + - HRDEM-RedRiver + styles: + type: string + enum: + - default + tileMatrixSets: + type: string + enum: + - WebMercatorQuad + - WorldCRS84Quad + - GNOSISGlobalGrid + - WorldMercatorWGS84Quad + Custom CRS projections and datums: + title: Custom CRS projections and datums + required: + - datums + - methods + type: object + properties: + methods: + type: object + additionalProperties: + $ref: "#/components/schemas/Custom CRS projections and datums_methods" + description: "The list of available projection operation methods for the `crs-proj-method` query parameter of the API. The properties in this dictionary object are the available values, and correspond to safe CURIEs if a URI is registered for the method." + datums: + type: object + additionalProperties: + $ref: "#/components/schemas/Custom CRS projections and datums_datums" + description: "The list of available datums for the `crs-datum` query parameter of the API. The properties in this dictionary object are the available values, and correspond to safe CURIEs if a URI is registered for the method." + parameters: + type: object + additionalProperties: + $ref: "#/components/schemas/Custom CRS projections and datums_parameters" + description: A list of global method parameters that can be referenced from individual methods supporting them using the "$ref" JSON Pointer mechanism. + description: "The list of available projection operation methods, parameters and datums for custom CRS definitions" + extent_spatial_grid: + type: object + properties: + coordinates: + minItems: 1 + type: array + description: |- + List of coordinates along the dimension for which data organized as an irregular grid in the collection is available + (e.g., 2, 10, 80, 100). + example: + - 2 + - 10 + - 80 + - 100 + items: + oneOf: + - type: string + nullable: true + - type: number + cellsCount: + type: integer + description: |- + Number of samples available along the dimension for data organized as a regular grid. + For values representing the whole area of contiguous cells spanning _resolution_ units along the dimension, this will be (_upperBound_ - _lowerBound_) / _resolution_. + For values representing infinitely small point cells spaced by _resolution_ units along the dimension, this will be (_upperBound_ - _lowerBound_) / _resolution_ + 1. + example: 50 + resolution: + description: Resolution of regularly gridded data along the dimension in the collection + example: 0.0006866455078 + oneOf: + - type: string + nullable: true + - type: number + extent_spatial: + type: object + properties: + bbox: + minItems: 1 + type: array + description: |- + One or more bounding boxes that describe the spatial extent of the dataset. + + The first bounding box describes the overall spatial + extent of the data. All subsequent bounding boxes describe + more precise bounding boxes, e.g., to identify clusters of data. + Clients only interested in the overall spatial extent will + only need to access the first item in each array. + items: + type: array + description: |- + Each bounding box is provided as four or six numbers, depending on + whether the coordinate reference system includes a vertical axis + (height or depth): + + * Lower left corner, coordinate axis 1 + * Lower left corner, coordinate axis 2 + * Minimum value, coordinate axis 3 (optional) + * Upper right corner, coordinate axis 1 + * Upper right corner, coordinate axis 2 + * Maximum value, coordinate axis 3 (optional) + + If the value consists of four numbers, the coordinate reference system is + WGS 84 longitude/latitude (http://www.opengis.net/def/crs/OGC/1.3/CRS84) + unless a different coordinate reference system is specified in `crs` property. + + If the value consists of six numbers, the coordinate reference system is WGS 84 + longitude/latitude/ellipsoidal height (http://www.opengis.net/def/crs/OGC/0/CRS84h) + unless a different coordinate reference system is specified in `crs` property. + + For WGS 84 longitude/latitude the values are in most cases the sequence of + minimum longitude, minimum latitude, maximum longitude and maximum latitude. + However, in cases where the box spans the antimeridian the first value + (west-most box edge) is larger than the third value (east-most box edge). + + If the vertical axis is included, the third and the sixth number are + the bottom and the top of the 3-dimensional bounding box. + + If a feature has multiple spatial geometry properties, it is the decision of the + server whether only a single spatial geometry property is used to determine + the extent or all relevant geometries. + example: + - -180 + - -90 + - 180 + - 90 + items: + type: number + storageCrsBbox: + minItems: 1 + type: array + description: |- + One or more bounding boxes that describe the spatial extent of the dataset in the storage (native) CRS (`storageCrs` property). + + The first bounding box describes the overall spatial + extent of the data. All subsequent bounding boxes describe + more precise bounding boxes, e.g., to identify clusters of data. + Clients only interested in the overall spatial extent will + only need to access the first item in each array. + items: + type: array + description: |- + Each bounding box is provided as four or six numbers, depending on + whether the coordinate reference system includes a vertical axis + (height or depth): + + * Lower left corner, coordinate axis 1 + * Lower left corner, coordinate axis 2 + * Minimum value, coordinate axis 3 (optional) + * Upper right corner, coordinate axis 1 + * Upper right corner, coordinate axis 2 + * Maximum value, coordinate axis 3 (optional) + example: + - -180 + - -90 + - 180 + - 90 + items: + type: number + crs: + type: string + description: |- + Coordinate reference system of the coordinates of the `bbox` property. + The default reference system is WGS 84 longitude/latitude. + WGS 84 longitude/latitude/ellipsoidal height for coordinates with height. + For non-terrestrial coordinate reference system, another CRS may be specified. + default: http://www.opengis.net/def/crs/OGC/1.3/CRS84 + enum: + - http://www.opengis.net/def/crs/OGC/1.3/CRS84 + - http://www.opengis.net/def/crs/OGC/0/CRS84h + grid: + maxItems: 3 + minItems: 2 + type: array + description: |- + Provides information about the limited availability of data within the collection organized + as a grid (regular or irregular) along each spatial dimension. + items: + $ref: "#/components/schemas/extent_spatial_grid" + description: The spatial extent of the data in the collection. + extent_temporal_grid: + type: object + properties: + coordinates: + minItems: 1 + type: array + description: |- + List of coordinates along the temporal dimension for which data organized as an irregular grid in the collection is available + (e.g., "2017-11-14T09:00Z","2017-11-14T12:00Z","2017-11-14T15:00Z","2017-11-14T18:00Z","2017-11-14T21:00Z"). + example: + - - 2020-11-12T12:15Z + - 2020-11-12T12:30Z + - 2020-11-12T12:45Z + items: + type: string + nullable: true + cellsCount: + type: integer + description: |- + Number of samples available along the temporal dimension for data organized as a regular grid. + For values representing the whole area of contiguous cells spanning _resolution_ units along the dimension, this will be (_upperBound_ - _lowerBound_) / _resolution_. + For values representing infinitely small point cells spaced by _resolution_ units along the dimension, this will be (_upperBound_ - _lowerBound_) / _resolution_ + 1. + example: 50 + resolution: + description: Resolution of regularly gridded data along the temporal dimension in the collection + example: PT1H + oneOf: + - type: string + nullable: true + - type: number + description: Provides information about the limited availability of data within the collection organized as a grid (regular or irregular) along the temporal dimension. + extent_temporal: + type: object + properties: + interval: + minItems: 1 + type: array + description: |- + One or more time intervals that describe the temporal extent of the dataset. + In the Core only a single time interval is supported. + + Extensions may support multiple intervals. + The first time interval describes the overall + temporal extent of the data. All subsequent time intervals describe + more precise time intervals, e.g., to identify clusters of data. + Clients only interested in the overall extent will only need + to access the first item in each array. + items: + maxItems: 2 + minItems: 2 + type: array + description: |- + Begin and end times of the time interval. The timestamps are in the + temporal coordinate reference system specified in `trs`. By default + this is the Gregorian calendar, expressed using RFC 3339 section 5.6. + Note that these times may be specified using time zone offsets to UTC time other than zero. + + The value `null` for start or end time is supported and indicates a half-bounded time interval. + example: + - 2011-11-11T12:22:11Z + - 2011-11-11T08:22:11-04:00 + - null + items: + type: string + format: date-time + nullable: true + trs: + type: string + description: |- + Coordinate reference system of the coordinates in the temporal extent + (property `interval`). The default reference system is the Gregorian calendar. + In the Core this is the only supported temporal coordinate reference system. + Extensions may support additional temporal coordinate reference systems and add + additional enum values. + default: http://www.opengis.net/def/uom/ISO-8601/0/Gregorian + enum: + - http://www.opengis.net/def/uom/ISO-8601/0/Gregorian + grid: + $ref: "#/components/schemas/extent_temporal_grid" + description: The temporal extent of the features in the collection. + tileSet_layers: + required: + - dataType + - id + type: object + properties: + title: + type: string + description: "Title of this tile matrix set, normally used for display to a human" + description: + type: string + description: "Brief narrative description of this tile matrix set, normally available for display to a human" + keywords: + type: string + description: Unordered list of one or more commonly used or formalized word(s) or phrase(s) used to describe this layer + id: + type: string + description: Unique identifier of the Layer. Implementation of 'identifier' + dataType: + allOf: + - description: Type of data represented in the layer + - $ref: "#/components/schemas/dataType" + geometryDimension: + maximum: 3 + minimum: 0 + type: integer + description: "The geometry dimension of the features shown in this layer (0: points, 1: curves, 2: surfaces, 3: solids), unspecified: mixed or unknown" + featureType: + type: string + description: Feature type identifier. Only applicable to layers of datatype 'geometries' + attribution: + type: string + description: Short reference to recognize the author or provider + license: + type: string + description: License applicable to the tiles + pointOfContact: + type: string + description: "Useful information to contact the authors or custodians for the layer (e.g. e-mail address, a physical address, phone numbers, etc)" + publisher: + type: string + description: Organization or individual responsible for making the layer available + theme: + type: string + description: Category where the layer can be grouped + crs: + allOf: + - description: Coordinate Reference System (CRS) + - $ref: "#/components/schemas/crs" + epoch: + type: number + description: Epoch of the Coordinate Reference System (CRS) + minScaleDenominator: + type: number + description: Minimum scale denominator for usage of the layer + maxScaleDenominator: + type: number + description: Maximum scale denominator for usage of the layer + minCellSize: + type: number + description: Minimum cell size for usage of the layer + maxCellSize: + type: number + description: Maximum cell size for usage of the layer + maxTileMatrix: + type: string + description: TileMatrix identifier associated with the minScaleDenominator + minTileMatrix: + type: string + description: TileMatrix identifier associated with the maxScaleDenominator + boundingBox: + allOf: + - description: Minimum bounding rectangle surrounding the layer + - $ref: "#/components/schemas/2DBoundingBox" + created: + allOf: + - description: When the layer was first produced + - $ref: "#/components/schemas/timeStamp" + updated: + allOf: + - description: Last layer change/revision + - $ref: "#/components/schemas/timeStamp" + style: + allOf: + - description: Style used to generate the layer in the tileset + - $ref: "#/components/schemas/tileSet/properties/style/allOf/1" + geoDataClasses: + type: array + description: URI identifying a class of data contained in this layer (useful to determine compatibility with styles or processes) + items: + type: string + propertiesSchema: + allOf: + - description: Properties represented by the features in this layer. Can be the attributes of a feature dataset (datatype=geometries) or the rangeType of a coverage (datatype=coverage) + - required: + - properties + - type + type: object + properties: + type: + type: string + enum: + - object + required: + minItems: 1 + type: array + description: Implements 'multiplicity' by citing property 'name' defined as 'additionalProperties' + items: + type: string + properties: + type: object + additionalProperties: + type: object + properties: + title: + type: string + description: + type: string + description: Implements 'description' + type: + type: string + enum: + - array + - boolean + - integer + - "null" + - number + - object + - string + enum: + minItems: 1 + uniqueItems: true + type: array + description: Implements 'acceptedValues' + items: {} + format: + type: string + description: Complements implementation of 'type' + contentMediaType: + type: string + description: Implements 'mediaType' + maximum: + type: number + description: Implements 'range' + exclusiveMaximum: + type: number + description: Implements 'range' + minimum: + type: number + description: Implements 'range' + exclusiveMinimum: + type: number + description: Implements 'range' + pattern: + type: string + format: regex + maxItems: + minimum: 0 + type: integer + description: Implements 'upperMultiplicity' + minItems: + minimum: 0 + type: integer + description: Implements 'lowerMultiplicity' + default: 0 + x-ogc-definition: + type: string + format: uri + x-ogc-unit: + type: string + x-ogc-unitLang: + type: string + format: uri + x-ogc-propertySeq: + minimum: 0 + type: integer + description: No property names are defined but any property name they should be described by JSON Schema. So 'additionalProperties' implements 'name'. + default: {} + description: Attributes of the features or rangetypes of a coverage. Defined by a subset of the JSON Schema for the properties of a feature + links: + minItems: 1 + type: array + description: "Links related to this layer. Possible link 'rel' values are: 'geodata' for a URL pointing to the collection of geospatial data." + items: + $ref: "#/components/schemas/link" + tileMatrixSet_variableMatrixWidths: + required: + - coalesce + - maxTileRow + - minTileRow + type: object + properties: + coalesce: + multipleOf: 1 + minimum: 2 + type: number + description: Number of tiles in width that coalesce in a single tile for these rows + format: integer + minTileRow: + multipleOf: 1 + minimum: 0 + type: number + description: First tile row where the coalescence factor applies for this tilematrix + format: integer + maxTileRow: + multipleOf: 1 + minimum: 0 + type: number + description: Last tile row where the coalescence factor applies for this tilematrix + format: integer + description: Variable Matrix Width data structure + tileMatrixSet_tileMatrices: + required: + - cellSize + - id + - matrixHeight + - matrixWidth + - pointOfOrigin + - scaleDenominator + - tileHeight + - tileWidth + type: object + properties: + title: + type: string + description: "Title of this tile matrix, normally used for display to a human" + description: + type: string + description: "Brief narrative description of this tile matrix set, normally available for display to a human" + keywords: + type: array + description: Unordered list of one or more commonly used or formalized word(s) or phrase(s) used to describe this dataset + items: + type: string + id: + type: string + description: Identifier selecting one of the scales defined in the TileMatrixSet and representing the scaleDenominator the tile. Implementation of 'identifier' + scaleDenominator: + type: number + description: Scale denominator of this tile matrix + cellSize: + type: number + description: Cell size of this tile matrix + cornerOfOrigin: + type: string + description: "The corner of the tile matrix (_topLeft_ or _bottomLeft_) used as the origin for numbering tile rows and columns. This corner is also a corner of the (0, 0) tile." + default: topLeft + enum: + - topLeft + - bottomLeft + pointOfOrigin: + allOf: + - description: "Precise position in CRS coordinates of the corner of origin (e.g. the top-left corner) for this tile matrix. This position is also a corner of the (0, 0) tile. In previous version, this was 'topLeftCorner' and 'cornerOfOrigin' did not exist." + - $ref: "#/components/schemas/2DPoint" + tileWidth: + multipleOf: 1 + minimum: 1 + type: number + description: Width of each tile of this tile matrix in pixels + format: integer + tileHeight: + multipleOf: 1 + minimum: 1 + type: number + description: Height of each tile of this tile matrix in pixels + format: integer + matrixHeight: + multipleOf: 1 + minimum: 1 + type: number + description: Width of the matrix (number of tiles in width) + format: integer + matrixWidth: + multipleOf: 1 + minimum: 1 + type: number + description: Height of the matrix (number of tiles in height) + format: integer + variableMatrixWidths: + type: array + description: Describes the rows that has variable matrix width + items: + $ref: "#/components/schemas/tileMatrixSet_variableMatrixWidths" + description: "A tile matrix, usually corresponding to a particular zoom level of a TileMatrixSet." + Custom CRS projections and datums_parameters: + type: object + properties: + title: + type: string + description: A title for this method parameter + description: + type: string + description: Brief narrative description of this method parameter + Custom CRS projections and datums_methods: + type: object + properties: + title: + type: string + description: A title for this projection operation method + description: + type: string + description: Brief narrative description of this projection operation method + parameters: + type: object + additionalProperties: + $ref: "#/components/schemas/Custom CRS projections and datums_parameters" + description: "The list of available method parmaeters for the `crs-proj-params` query parameter of the API when using this method. The properties in this dictionary object are the available values, and correspond to safe CURIEs if a URI is registered for the method. \"$ref\" may be used to refer to global parameters in the \"parameters\" property of this document." + Custom CRS projections and datums_datums: + required: + - ellipsoid + type: object + properties: + title: + type: string + description: A title for this datum. + description: + type: string + description: Brief narrative description of this datum + ellipsoid: + type: string + description: The identifier (safe CURIE if a URI exists) for the ellipsoid associated with this datum. + responses: + NotFound: + description: "The requested resource does not exist on the server. For example, a path parameter had an incorrect value." + content: + application/json: + schema: + $ref: "#/components/schemas/exception" + text/html: + schema: + type: string + NotAcceptable: + description: "Content negotiation failed. For example, the `Accept` header submitted in the request did not support any of the media types supported by the server for the requested resource." + content: + application/json: + schema: + $ref: "#/components/schemas/exception" + text/html: + schema: + type: string + ServerError: + description: A server error occurred. + content: + application/json: + schema: + $ref: "#/components/schemas/exception" + text/html: + schema: + type: string + InvalidParameter: + description: A query parameter has an invalid value. + content: + application/json: + schema: + $ref: "#/components/schemas/exception" + text/html: + schema: + type: string + Exception: + description: An error occurred. + content: + application/json: + schema: + $ref: "#/components/schemas/exception" + text/html: + schema: + type: string + LandingPage: + description: |- + The landing page provides links to the API definition (link relation `service-desc`, in this case path `/api`), + to the Conformance declaration (path `/conformance`, link relation `conformance`), and to the Collections of geospatial data (path `/collections`, link relation `data`). + content: + application/json: + schema: + $ref: "#/components/schemas/landingPage" + example: + title: Buildings in Bonn + description: Access to data about buildings in the city of Bonn via a Web API that conforms to the OGC API - Maps specification. + links: + - href: http://data.example.org/ + rel: self + type: application/json + title: this document + - href: http://data.example.org/api + rel: service-desc + type: application/vnd.oai.openapi+json;version=3.0 + title: the API definition + - href: http://data.example.org/api.html + rel: service-doc + type: text/html + title: the API documentation + - href: http://data.example.org/conformance + rel: http://www.opengis.net/def/rel/ogc/1.0/conformance + type: application/json + title: OGC API conformance classes implemented by this service + - href: http://data.example.org/collections + rel: http://www.opengis.net/def/rel/ogc/1.0/data + type: application/json + title: Information about the collections + text/html: + schema: + type: string + Conformance: + description: The URIs of all conformance classes supported by the server + content: + application/json: + schema: + example: + conformsTo: + - http://www.opengis.net/spec/ogcapi-common-1/1.0/conf/core + - http://www.opengis.net/spec/ogcapi-common-1/1.0/conf/landing-page + - http://www.opengis.net/spec/ogcapi-common-1/1.0/conf/json + - http://www.opengis.net/spec/ogcapi-common-1/1.0/conf/html + - http://www.opengis.net/spec/ogcapi-common-1/1.0/conf/oas30 + - http://www.opengis.net/spec/ogcapi-common-2/1.0/conf/collections + - https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/core + - https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/tilesets + - https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/background + - https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/collections-selection + - https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/scaling + - https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/display-resolution + - https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/spatial-subsetting + - https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/datetime + - https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/general-subsetting + - https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/crs + - https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/orientation + - https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/projection + - https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/collection-map + - https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/dataset-map + - https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/styled-map + - https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/png + - https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/jpeg + - https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/jpegxl + - https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/tiff + - https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/svg + - https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/html + - https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/api-operations + allOf: + - $ref: "#/components/schemas/confClasses" + API: + description: The OpenAPI definition of the API. + content: + application/vnd.oai.openapi+json;version=3.0: + schema: + type: object + text/html: + schema: + type: string + Enumeration: + description: An enumerated list of valid string values for API parameters. + content: + application/json: + schema: + $ref: "#/components/schemas/enumeration" + text/html: + schema: + type: string + CollectionsList: + description: |- + The collections of (mostly geospatial) data available from this API. The dataset contains one or more collections. This resource provides information about and access to the collections. The response contains the list of collections. Each collection is accessible via one or more OGC API set of specifications, for which a link to relevant accessible resources, e.g. /collections/{collectionId}/(items, coverage, map, tiles...) is provided, with the corresponding relation type, as well as key information about the collection. This information includes: + * a local identifier for the collection that is unique for the dataset; + * a list of coordinate reference systems (CRS) in which data may be returned by the server. The first CRS is the default coordinate reference system (the default is always WGS 84 with axis order longitude/latitude); + * an optional title and description for the collection; + * an optional extent that can be used to provide an indication of the spatial and temporal extent of the collection - typically derived from the data; + * for collections accessible via the Features or Records API, an optional indicator about the type of the items in the collection (the default value, if the indicator is not provided, is 'feature'). + content: + application/json: + schema: + $ref: "#/components/schemas/collections" + example: + links: + - href: http://data.example.org/collections.json + rel: self + type: application/json + title: this document + - href: http://data.example.org/collections.html + rel: alternate + type: text/html + title: this document as HTML + - href: http://schemas.example.org/1.0/buildings.xsd + rel: describedby + type: application/xml + title: GML application schema for Acme Corporation building data + - href: http://download.example.org/buildings.gpkg + rel: enclosure + type: application/geopackage+sqlite3 + title: Bulk download (GeoPackage) + length: 472546 + collections: + - id: buildings + title: Buildings + description: Buildings in the city of Bonn. + extent: + spatial: + bbox: + - - 7.01 + - 50.63 + - 7.22 + - 50.78 + temporal: + interval: + - - 2010-02-15T12:34:56Z + - null + links: + - href: http://data.example.org/collections/buildings/items + rel: items + type: application/geo+json + title: Buildings + - href: http://data.example.org/collections/buildings/items.html + rel: items + type: text/html + title: Buildings + - href: https://creativecommons.org/publicdomain/zero/1.0/ + rel: license + type: text/html + title: CC0-1.0 + - href: https://creativecommons.org/publicdomain/zero/1.0/rdf + rel: license + type: application/rdf+xml + title: CC0-1.0 + text/html: + schema: + type: string + Collection: + description: |- + Information about a particular collection of (mostly geospatial) data available from this API. The collection is accessible via one or more OGC API set of specifications, for which a link to relevant accessible resources, e.g. /collections/{collectionId}/(items, coverage, map, tiles...) is contained in the response, with the corresponding relation type, as well as key information about the collection. This information includes: + * a local identifier for the collection that is unique for the dataset; + * a list of coordinate reference systems (CRS) in which data may be returned by the server. The first CRS is the default coordinate reference system (the default is always WGS 84 with axis order longitude/latitude); + * an optional title and description for the collection; + * an optional extent that can be used to provide an indication of the spatial and temporal extent of the collection - typically derived from the data; + * for collections accessible via the Features or Records API, an optional indicator about the type of the items in the collection (the default value, if the indicator is not provided, is 'feature'). + content: + application/json: + schema: + $ref: "#/components/schemas/collectionDesc" + example: + id: buildings + title: Buildings + description: Buildings in the city of Bonn. + extent: + spatial: + bbox: + - - 7.01 + - 50.63 + - 7.22 + - 50.78 + temporal: + interval: + - - 2010-02-15T12:34:56Z + - null + links: + - href: http://data.example.org/collections/buildings/items + rel: items + type: application/geo+json + title: Buildings + - href: http://data.example.org/collections/buildings/items.html + rel: items + type: text/html + title: Buildings + - href: https://creativecommons.org/publicdomain/zero/1.0/ + rel: license + type: text/html + title: CC0-1.0 + - href: https://creativecommons.org/publicdomain/zero/1.0/rdf + rel: license + type: application/rdf+xml + title: CC0-1.0 + text/html: + schema: + type: string + Map: + description: A map image returned as a response. + content: + image/png: + schema: + type: string + format: binary + image/jpeg: + schema: + type: string + format: binary + image/tiff; application=geotiff: + schema: + type: string + format: binary + EmptyMap: + description: No data available for this map extent. + TileSetsList: + description: List of available tilesets. + content: + application/json: + schema: + required: + - tilesets + type: object + properties: + links: + type: array + items: + $ref: "#/components/schemas/link" + tilesets: + type: array + items: + $ref: "#/components/schemas/tileSet-item" + text/html: + schema: + type: string + TileSet: + description: Description of the tileset + content: + application/json: + schema: + $ref: "#/components/schemas/tileSet" + text/html: + schema: + type: string + MapTile: + description: A map tile image returned as a response. + content: + image/png: + schema: + type: string + format: binary + image/jpeg: + schema: + type: string + format: binary + image/tiff; application=geotiff: + schema: + type: string + format: binary + EmptyTile: + description: No data available for this tile. + TileMatrixSetsList: + description: List of tile matrix sets (tiling schemes). + content: + application/json: + schema: + type: object + properties: + tileMatrixSets: + type: array + items: + $ref: "#/components/schemas/tileMatrixSet-item" + text/html: + schema: + type: string + TileMatrixSet: + description: tile matrix set + content: + application/json: + schema: + $ref: "#/components/schemas/tileMatrixSet" + parameters: + f-metadata: + name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + collectionId-all: + name: collectionId + in: path + description: Local identifier of a collection + required: true + schema: + $ref: "#/components/schemas/all-collections" + bbox: + name: bbox + in: query + description: |- + Only resources that have a geometry that intersects the bounding box are selected. The bounding box is provided as four or six numbers, depending on whether the coordinate reference system includes a vertical axis (elevation or depth): + * Lower left corner, coordinate axis 1 * Lower left corner, coordinate axis 2 * Minimum value, coordinate axis 3 (optional) * Upper right corner, coordinate axis 1 * Upper right corner, coordinate axis 2 * Maximum value, coordinate axis 3 (optional) + If the value consists of four numbers, the coordinate reference system is WGS84 longitude/latitude (http://www.opengis.net/def/crs/OGC/1.3/CRS84) unless a different coordinate reference system is specified in the parameter `bbox-crs`. + If the value consists of six numbers, the coordinate reference system is WGS 84 longitude/latitude/ellipsoidal height (http://www.opengis.net/def/crs/OGC/0/CRS84h) unless a different coordinate reference system is specified in a parameter `bbox-crs`. + For WGS84 longitude/latitude the values are in most cases the sequence of minimum longitude, minimum latitude, maximum longitude and maximum latitude. However, in cases where the box spans the antimeridian the first value (west-most box edge) is larger than the third value (east-most box edge). + If the vertical axis is included, the third and the sixth number are the bottom and the top of the 3-dimensional bounding box. + If a resource has multiple spatial geometry properties, it is the decision of the server whether only a single spatial geometry property is used to determine the extent or all relevant geometries. + required: false + style: form + explode: false + schema: + type: array + items: + type: number + datetime: + name: datetime + in: query + description: |- + Either a date-time or an interval. Date and time expressions adhere to RFC 3339, section 5.6. Intervals may be bounded or half-bounded (double-dots at start or end). Server implementations may or may not support times expressed using time offsets from UTC, but need to support UTC time with the notation ending with a Z. + Examples: + * A date-time: "2018-02-12T23:20:50Z" * A bounded interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" * Half-bounded intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z" + Only resources that have a temporal property that intersects the value of `datetime` are selected. + If a feature has multiple temporal properties, it is the decision of the server whether only a single temporal property is used to determine the extent or all relevant temporal properties. + required: false + style: form + explode: false + schema: + type: string + crs: + name: crs + in: query + description: reproject the output to the given crs + required: false + style: form + explode: true + schema: + type: string + bbox-crs: + name: bbox-crs + in: query + description: crs for the specified bbox + required: false + style: form + explode: true + schema: + type: string + subset-crs: + name: subset-crs + in: query + description: crs for the specified subset + required: false + style: form + explode: true + schema: + type: string + collections: + name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + subset: + name: subset + in: query + description: | + Retrieve only part of the data by slicing or trimming along one or more axis + For trimming: {axisAbbrev}({low}:{high}) (preserves dimensionality) + For slicing: {axisAbbrev}({value}) (reduces dimensionality) + An asterisk (`*`) can be used instead of {low} or {high} to indicate the minimum/maximum value. + For a temporal dimension, a single asterisk can be used to indicate the high value. + Support for `*` is required for time, but optional for spatial and other dimensions. + required: false + style: form + explode: false + schema: + type: array + items: + type: string + bgcolor: + name: bgcolor + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the background color (default to 0x9C9C9C gray). If alpha is not specified, full opacity is assumed." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + transparent: + name: transparent + in: query + description: "Background transparency of map (defaults to `true` without a `bgcolor` specified, but to `false` when a `bgcolor` is used)." + required: false + style: form + explode: false + schema: + type: boolean + default: true + void-color: + name: void-color + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the void color for parts of the map outside of the valid area of the projection / CRS. If not specified, this defaults to the same as `bgcolor`." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + void-transparent: + name: void-transparent + in: query + description: Background transparency for parts of the map outside of the valid areas of the CRS / projection (defaults to the same as `transparent` if not specified). + required: false + style: form + explode: false + schema: + type: boolean + default: true + width: + name: width + in: query + description: "Width of the map in pixels. If omitted and `height` is specified, defaults to the width maintaining a 1:1 aspect ratio. If both `width` and `height` are omitted, the server will select default dimensions. When used together with the `center` and/or `scale-denominator` parameter, `width` takes on a subsetting role rather than scaling (resampling), defining the horizontal portion of the map to subset based on the scale (native scale, or specified by `scale-denominator`) and display resolution (0.28 mm/pixel, or specified by `mm-per-pixel`)." + required: false + style: form + explode: false + schema: + type: integer + height: + name: height + in: query + description: "Height of the map in pixels. If omitted and `width` is specified, defaults to the height maintaining a 1:1 aspect ratio. If both `width` and `height` are omitted, the server will select default dimensions. When used together with the `center` and/or `scale-denominator` parameter, `height` takes on a subsetting role rather than scaling (resampling), defining the vertical portion of the map to subset based on the scale (native scale, or specified by `scale-denominator`) and display resolution (0.28 mm/pixel, or specified by `mm-per-pixel`)." + required: false + style: form + explode: false + schema: + type: integer + center: + name: center + in: query + description: "Coordinates of center point for subsetting, in conjunction with the `width` and/or `height` parameters, taking into consideration the scale and display resolution of the map. The center coordinates are comma-separated and interpreted as [ogc:CRS84], unless the `center-crs` parameter specifies otherwise." + required: false + style: form + explode: false + schema: + maxItems: 2 + minItems: 2 + type: array + items: + type: number + center-crs: + name: center-crs + in: query + description: CRS for the specified center point + required: false + style: form + explode: true + schema: + type: string + scale-denominator: + name: scale-denominator + in: query + description: "Scale denominator of the map specifying to how many units in the real world one of the same unit on the map corresponds, as printed or displayed, taking into account the display resolution (`mm-per-pixel` or 0.28 mm/pixel default). This parameter can only be used together with the `width` or `height` parameters (which provide an alternative mechanism to control the scale) if the implementation also supports subsetting, in which case those `width` and `height` parameters then control the subset of the map returned rather than the scale. If `scale-denominator` is omitted, the scale is implied from the dimensions of the returned map compared to its spatial subset area." + required: false + style: form + explode: false + schema: + type: number + mm-per-pixel: + name: mm-per-pixel + in: query + description: "Display resolution of the target rendering device in millimeters per pixel. This parameter controls the relationship between the dimensions of the resulting map in pixels and the scale of the map. The display resolution is taken into account for applying symbology rules, for the `scale-denominator` parameter, and for the spatial subsetting using a `center`, `width` and `height` parameters." + required: false + style: form + explode: false + schema: + type: number + default: 0.28 + orientation: + name: orientation + in: query + description: "Orientation in degrees by which the content of the map is to be rotated around the center of the subset area as pivot point in a counter-clockwise direction, resulting in the viewing perspective being rotated by the same orientation in a clockwise direction." + required: false + style: form + explode: false + schema: + type: number + default: 0 + crs-proj-method: + name: crs-proj-method + in: query + description: Projection operation method for a custom projection CRS. + required: false + style: form + explode: false + schema: + type: string + crs-proj-center: + name: crs-proj-center + in: query + description: Projection center for a custom projection CRS corresponding to specific projection operation method parameters for latitude and longitude. + required: false + style: form + explode: false + schema: + type: string + crs-proj-params: + name: crs-proj-params + in: query + description: Operation method parameters for a custom projection CRS. + required: false + style: form + explode: false + schema: + type: string + crs-datum: + name: crs-datum + in: query + description: "Datum for a custom projection CRS, implying a particular ellipsoid." + required: false + style: form + explode: false + schema: + type: string + f-map: + name: f + in: query + description: "The format of the map response (e.g. png). Accepted values are 'png', 'jpg' or 'tiff' (GeoTIFF)." + required: false + style: form + explode: false + schema: + type: string + enum: + - png + - jpg + - tiff + styleId: + name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + $ref: "#/components/schemas/styles" + styleId-collection: + name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + type: string + tileMatrix: + name: tileMatrix + in: path + description: |- + Identifier selecting one of the scales defined in the TileMatrixSet and representing the scaleDenominator the tile. For example, + Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15. + required: true + schema: + type: string + example: "5" + tileRow: + name: tileRow + in: path + description: "Row index of the tile on the selected TileMatrix. It cannot exceed the MatrixWidth-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 10 + tileCol: + name: tileCol + in: path + description: "Column index of the tile on the selected TileMatrix. It cannot exceed the MatrixHeight-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 15 + tileMatrixSetId: + name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + f-mapTile: + name: f + in: query + description: "The format of the map tile response (e.g. png). Accepted values are 'png', 'jpg' or 'tiff' (GeoTIFF)." + required: false + style: form + explode: false + schema: + type: string + enum: + - png + - jpg + - tiff diff --git a/docs/OGC-ogcapi-tiles-1-example-1-1.0.0-resolved.yaml b/docs/OGC-ogcapi-tiles-1-example-1-1.0.0-resolved.yaml new file mode 100644 index 0000000..c0e18c2 --- /dev/null +++ b/docs/OGC-ogcapi-tiles-1-example-1-1.0.0-resolved.yaml @@ -0,0 +1,4324 @@ +openapi: 3.0.0 +info: + title: "A sample API conforming to version 1.0.0 of the OGC API - Tiles - Part 1: Core Standard" + description: |- + Common components used in the + ["OGC API - Tiles - Part 1: Core standard"](https://docs.opengeospatial.org/is/20-057/20-057.html). + + OGC API - Tiles - Part 1: Core 1.0.0 is an OGC Standard. + Copyright (c) 2022 Open Geospatial Consortium. + To obtain additional rights of use, visit http://www.opengeospatial.org/legal/ . + + This is an informative document. The building blocks in this document are also available on the + [OGC](https://schemas.opengis.net/ogcapi/tiles/part1/1.0/openapi/ogcapi-tiles-1.yaml) schema repository. + contact: + name: Open Geospatial Consortium (OGC) + url: https://www.ogc.org/contacts + email: standards-team@ogc.org + license: + name: OGC License + url: http://www.opengeospatial.org/legal/ + version: 1.0.0 + x-logo: + url: https://www.ogc.org/pub/www/files/OGC_Logo_2D_Blue_x_0_0.png +servers: +- url: / +paths: + /: + get: + tags: + - Landing Page + summary: Retrieve the OGC API landing page for this service. + operationId: getLandingPage + parameters: + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/LandingPage" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /conformance: + get: + tags: + - Conformance + summary: Retrieve the set of OGC API conformance classes that are supported by this service. + operationId: getConformance + parameters: + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/Conformance" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /api: + get: + tags: + - API + summary: Retrieve this API definition. + operationId: getAPI + parameters: + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/API" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /api/all-collections: + get: + tags: + - API + summary: Retrieve the list of collections available from this API implementation & deployment. + operationId: getAPICollections + parameters: + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/Enumeration" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /api/coverage-collections: + get: + tags: + - API + summary: Retrieve the list of coverages collections available from this API implementation & deployment. + operationId: getAPICoverageCollections + parameters: + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/Enumeration" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /api/vectorTiles-collections: + get: + tags: + - API + summary: Retrieve the list of collections supporting vector tiles available from this API implementation & deployment. + operationId: getAPIVectorTileCollections + parameters: + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/Enumeration" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /api/tileMatrixSets: + get: + tags: + - API + summary: Retrieve the list of shared TileMatrixSets available from this API implementation & deployment. + operationId: getAPITileMatrixSets + parameters: + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/Enumeration" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /api/styles: + get: + tags: + - API + summary: Retrieve the list of dataset styles available from this API implementation & deployment. + operationId: getAPIStyles + parameters: + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/Enumeration" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections: + get: + tags: + - Data Collections + summary: Retrieve the list of geospatial data collections available from this service. + operationId: getCollectionsList + parameters: + - name: datetime + in: query + description: |- + Either a date-time or an interval, half-bounded or bounded. Date and time expressions + adhere to RFC 3339. Half-bounded intervals are expressed using double-dots. + + Examples: + + * A date-time: "2018-02-12T23:20:50Z" + * A bounded interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" + * Half-bounded intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z" + + Only features that have a temporal property that intersects the value of + `datetime` are selected. + + If a feature has multiple temporal properties, it is the decision of the + server whether only a single temporal property is used to determine + the extent or all relevant temporal properties. + required: false + style: form + explode: false + schema: + type: string + - name: bbox + in: query + description: |- + Only features that have a geometry that intersects the bounding box are selected. The bounding box is provided as four or six numbers, depending on whether the coordinate reference system includes a vertical axis (height or depth): + * Lower left corner, coordinate axis 1 * Lower left corner, coordinate axis 2 * Minimum value, coordinate axis 3 (optional) * Upper right corner, coordinate axis 1 * Upper right corner, coordinate axis 2 * Maximum value, coordinate axis 3 (optional) + The coordinate reference system of the values is WGS 84 longitude/latitude (http://www.opengis.net/def/crs/OGC/1.3/CRS84) unless a different coordinate reference system is specified in the parameter `bbox-crs`. + For WGS 84 longitude/latitude the values are in most cases the sequence of minimum longitude, minimum latitude, maximum longitude and maximum latitude. However, in cases where the box spans the antimeridian the first value (west-most box edge) is larger than the third value (east-most box edge). + If the vertical axis is included, the third and the sixth number are the bottom and the top of the 3-dimensional bounding box. + If a feature has multiple spatial geometry properties, it is the decision of the server whether only a single spatial geometry property is used to determine the extent or all relevant geometries. + required: false + style: form + explode: false + schema: + type: array + items: + type: number + format: double + - name: limit + in: query + description: |- + The optional limit parameter limits the number of collections that are presented in the response document. + Only items are counted that are on the first level of the collection in the response document. Nested objects contained within the explicitly requested items shall not be counted. + * Minimum = 1 * Maximum = 10000 * Default = 10 + required: false + style: form + explode: false + schema: + maximum: 10000 + minimum: 1 + type: integer + default: 10 + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/CollectionsList" + /collections/{collectionId}: + get: + tags: + - Data Collections + summary: Retrieve the description of a collection available from this service. + operationId: getCollection + parameters: + - name: collectionId + in: path + description: Local identifier of a collection + required: true + schema: + $ref: "#/components/schemas/all-collections" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/Collection" + /tileMatrixSets: + get: + tags: + - Tiling Schemes + summary: Retrieve the list of available tiling schemes (tile matrix sets) + operationId: getTileMatrixSetsList + parameters: + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileMatrixSetsList" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /tileMatrixSets/{tileMatrixSetId}: + get: + tags: + - Tiling Schemes + summary: Retrieve the definition of the specified tiling scheme (tile matrix set) + operationId: getTileMatrixSet + parameters: + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileMatrixSet" + "404": + description: The requested tile matrix set id was not found + content: + application/json: + schema: + $ref: "#/components/schemas/exception" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /tiles: + get: + tags: + - Vector Tiles + summary: Retrieve a list of available vector tilesets for the dataset + operationId: .dataset.vector.getTileSetsList + parameters: + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileSetsList" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /tiles/{tileMatrixSetId}: + get: + tags: + - Vector Tiles + summary: Retrieve the vector tileset metadata for the whole dataset and the specified tiling scheme (tile matrix set) + operationId: .dataset.vector.getTileSet + parameters: + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileSet" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /tiles/{tileMatrixSetId}/{tileMatrix}/{tileRow}/{tileCol}: + get: + tags: + - Vector Tiles + summary: Retrieve a vector tile including one or more collections from the dataset. + operationId: .dataset.vector.getTile + parameters: + - name: tileMatrix + in: path + description: |- + Identifier selecting one of the scales defined in the TileMatrixSet and representing the scaleDenominator the tile. For example, + Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15. + required: true + schema: + type: string + example: "5" + - name: tileRow + in: path + description: "Row index of the tile on the selected TileMatrix. It cannot exceed the MatrixWidth-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 10 + - name: tileCol + in: path + description: "Column index of the tile on the selected TileMatrix. It cannot exceed the MatrixHeight-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 15 + - name: datetime + in: query + description: |- + Either a date-time or an interval, half-bounded or bounded. Date and time expressions + adhere to RFC 3339. Half-bounded intervals are expressed using double-dots. + + Examples: + + * A date-time: "2018-02-12T23:20:50Z" + * A bounded interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" + * Half-bounded intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z" + + Only features that have a temporal property that intersects the value of + `datetime` are selected. + + If a feature has multiple temporal properties, it is the decision of the + server whether only a single temporal property is used to determine + the extent or all relevant temporal properties. + required: false + style: form + explode: false + schema: + type: string + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/vectorTiles-collections" + - name: subset + in: query + description: | + Retrieve only part of the data by slicing or trimming along one or more axis + For trimming: {axisAbbrev}({low}:{high}) (preserves dimensionality) + An asterisk (`*`) can be used instead of {low} or {high} to indicate the minimum/maximum value. + For slicing: {axisAbbrev}({value}) (reduces dimensionality) + required: false + style: form + explode: false + schema: + type: array + items: + type: string + - name: crs + in: query + description: reproject the output to the given crs + required: false + style: form + explode: true + schema: + type: string + - name: subset-crs + in: query + description: crs for the specified subset + required: false + style: form + explode: true + schema: + type: string + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: The format of the vector tile response (e.g. json). Accepted values are 'mvt' (Mapbox Vector Tiles) or 'json' (GeoJSON). + required: false + style: form + explode: false + schema: + type: string + enum: + - mvt + - json + responses: + "200": + $ref: "#/components/responses/VectorTile" + "204": + $ref: "#/components/responses/EmptyTile" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /styles/{styleId}/tiles: + get: + tags: + - Vector Tiles + summary: Retrieve the list of vector tilesets intended for use with a specified style for the whole dataset + operationId: .dataset.style.vector.getTileSetsList + parameters: + - name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + $ref: "#/components/schemas/styles" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileSetsList" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /styles/{styleId}/tiles/{tileMatrixSetId}: + get: + tags: + - Vector Tiles + summary: Retrieve a vector tileset intended for use with a specified style of the whole dataset for the specified tiling scheme (tile matrix set) + operationId: .dataset.style.vector.getTileSet + parameters: + - name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + $ref: "#/components/schemas/styles" + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileSet" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /styles/{styleId}/tiles/{tileMatrixSetId}/{tileMatrix}/{tileRow}/{tileCol}: + get: + tags: + - Vector Tiles + summary: Retrieve vector tiles intended for use with a specified style + operationId: .dataset.style.vector.getTile + parameters: + - name: tileMatrix + in: path + description: |- + Identifier selecting one of the scales defined in the TileMatrixSet and representing the scaleDenominator the tile. For example, + Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15. + required: true + schema: + type: string + example: "5" + - name: tileRow + in: path + description: "Row index of the tile on the selected TileMatrix. It cannot exceed the MatrixWidth-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 10 + - name: tileCol + in: path + description: "Column index of the tile on the selected TileMatrix. It cannot exceed the MatrixHeight-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 15 + - name: datetime + in: query + description: |- + Either a date-time or an interval, half-bounded or bounded. Date and time expressions + adhere to RFC 3339. Half-bounded intervals are expressed using double-dots. + + Examples: + + * A date-time: "2018-02-12T23:20:50Z" + * A bounded interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" + * Half-bounded intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z" + + Only features that have a temporal property that intersects the value of + `datetime` are selected. + + If a feature has multiple temporal properties, it is the decision of the + server whether only a single temporal property is used to determine + the extent or all relevant temporal properties. + required: false + style: form + explode: false + schema: + type: string + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/vectorTiles-collections" + - name: subset + in: query + description: | + Retrieve only part of the data by slicing or trimming along one or more axis + For trimming: {axisAbbrev}({low}:{high}) (preserves dimensionality) + An asterisk (`*`) can be used instead of {low} or {high} to indicate the minimum/maximum value. + For slicing: {axisAbbrev}({value}) (reduces dimensionality) + required: false + style: form + explode: false + schema: + type: array + items: + type: string + - name: crs + in: query + description: reproject the output to the given crs + required: false + style: form + explode: true + schema: + type: string + - name: subset-crs + in: query + description: crs for the specified subset + required: false + style: form + explode: true + schema: + type: string + - name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + $ref: "#/components/schemas/styles" + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: The format of the vector tile response (e.g. json). Accepted values are 'mvt' (Mapbox Vector Tiles) or 'json' (GeoJSON). + required: false + style: form + explode: false + schema: + type: string + enum: + - mvt + - json + responses: + "200": + $ref: "#/components/responses/VectorTile" + "204": + $ref: "#/components/responses/EmptyTile" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/tiles: + get: + tags: + - Vector Tiles + summary: Retrieve a list of available vector tilesets for the specified collection. + operationId: .collection.vector.getTileSetsList + parameters: + - name: collectionId + in: path + description: Local identifier of a vector tile collection + required: true + schema: + $ref: "#/components/schemas/vectorTiles-collections" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileSetsList" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/tiles/{tileMatrixSetId}: + get: + tags: + - Vector Tiles + summary: Retrieve the vector tileset metadata for the specified collection and tiling scheme (tile matrix set) + operationId: .collection.vector.getTileSet + parameters: + - name: collectionId + in: path + description: Local identifier of a vector tile collection + required: true + schema: + $ref: "#/components/schemas/vectorTiles-collections" + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/vectorTiles-collections" + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileSet" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/tiles/{tileMatrixSetId}/{tileMatrix}/{tileRow}/{tileCol}: + get: + tags: + - Vector Tiles + summary: Retrieve a vector tile from a collection. + operationId: .collection.vector.getTile + parameters: + - name: tileMatrix + in: path + description: |- + Identifier selecting one of the scales defined in the TileMatrixSet and representing the scaleDenominator the tile. For example, + Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15. + required: true + schema: + type: string + example: "5" + - name: tileRow + in: path + description: "Row index of the tile on the selected TileMatrix. It cannot exceed the MatrixWidth-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 10 + - name: tileCol + in: path + description: "Column index of the tile on the selected TileMatrix. It cannot exceed the MatrixHeight-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 15 + - name: datetime + in: query + description: |- + Either a date-time or an interval, half-bounded or bounded. Date and time expressions + adhere to RFC 3339. Half-bounded intervals are expressed using double-dots. + + Examples: + + * A date-time: "2018-02-12T23:20:50Z" + * A bounded interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" + * Half-bounded intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z" + + Only features that have a temporal property that intersects the value of + `datetime` are selected. + + If a feature has multiple temporal properties, it is the decision of the + server whether only a single temporal property is used to determine + the extent or all relevant temporal properties. + required: false + style: form + explode: false + schema: + type: string + - name: collectionId + in: path + description: Local identifier of a vector tile collection + required: true + schema: + $ref: "#/components/schemas/vectorTiles-collections" + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/vectorTiles-collections" + - name: subset + in: query + description: | + Retrieve only part of the data by slicing or trimming along one or more axis + For trimming: {axisAbbrev}({low}:{high}) (preserves dimensionality) + An asterisk (`*`) can be used instead of {low} or {high} to indicate the minimum/maximum value. + For slicing: {axisAbbrev}({value}) (reduces dimensionality) + required: false + style: form + explode: false + schema: + type: array + items: + type: string + - name: crs + in: query + description: reproject the output to the given crs + required: false + style: form + explode: true + schema: + type: string + - name: subset-crs + in: query + description: crs for the specified subset + required: false + style: form + explode: true + schema: + type: string + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: The format of the vector tile response (e.g. json). Accepted values are 'mvt' (Mapbox Vector Tiles) or 'json' (GeoJSON). + required: false + style: form + explode: false + schema: + type: string + enum: + - mvt + - json + responses: + "200": + $ref: "#/components/responses/VectorTile" + "204": + $ref: "#/components/responses/EmptyTile" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/styles/{styleId}/tiles: + get: + tags: + - Vector Tiles + summary: Retrieve a list of vector tilesets for the specified collection intended for use with a specified style + operationId: .collection.style.vector.getTileSetsList + parameters: + - name: collectionId + in: path + description: Local identifier of a vector tile collection + required: true + schema: + $ref: "#/components/schemas/vectorTiles-collections" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + - name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + type: string + responses: + "200": + $ref: "#/components/responses/TileSetsList" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/styles/{styleId}/tiles/{tileMatrixSetId}: + get: + tags: + - Vector Tiles + summary: "Retrieve the vector tileset metadata for the specified collection, style and tiling scheme (tile matrix set)." + operationId: .collection.style.vector.getTileSet + parameters: + - name: collectionId + in: path + description: Local identifier of a vector tile collection + required: true + schema: + $ref: "#/components/schemas/vectorTiles-collections" + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/vectorTiles-collections" + - name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + type: string + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileSet" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/styles/{styleId}/tiles/{tileMatrixSetId}/{tileMatrix}/{tileRow}/{tileCol}: + get: + tags: + - Vector Tiles + summary: "Retrieve vector tiles for a specified collection, intended for use with a specified style" + operationId: .collection.style.vector.getTile + parameters: + - name: tileMatrix + in: path + description: |- + Identifier selecting one of the scales defined in the TileMatrixSet and representing the scaleDenominator the tile. For example, + Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15. + required: true + schema: + type: string + example: "5" + - name: tileRow + in: path + description: "Row index of the tile on the selected TileMatrix. It cannot exceed the MatrixWidth-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 10 + - name: tileCol + in: path + description: "Column index of the tile on the selected TileMatrix. It cannot exceed the MatrixHeight-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 15 + - name: datetime + in: query + description: |- + Either a date-time or an interval, half-bounded or bounded. Date and time expressions + adhere to RFC 3339. Half-bounded intervals are expressed using double-dots. + + Examples: + + * A date-time: "2018-02-12T23:20:50Z" + * A bounded interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" + * Half-bounded intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z" + + Only features that have a temporal property that intersects the value of + `datetime` are selected. + + If a feature has multiple temporal properties, it is the decision of the + server whether only a single temporal property is used to determine + the extent or all relevant temporal properties. + required: false + style: form + explode: false + schema: + type: string + - name: collectionId + in: path + description: Local identifier of a vector tile collection + required: true + schema: + $ref: "#/components/schemas/vectorTiles-collections" + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/vectorTiles-collections" + - name: subset + in: query + description: | + Retrieve only part of the data by slicing or trimming along one or more axis + For trimming: {axisAbbrev}({low}:{high}) (preserves dimensionality) + An asterisk (`*`) can be used instead of {low} or {high} to indicate the minimum/maximum value. + For slicing: {axisAbbrev}({value}) (reduces dimensionality) + required: false + style: form + explode: false + schema: + type: array + items: + type: string + - name: crs + in: query + description: reproject the output to the given crs + required: false + style: form + explode: true + schema: + type: string + - name: subset-crs + in: query + description: crs for the specified subset + required: false + style: form + explode: true + schema: + type: string + - name: bgcolor + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the background color (default to 0x9C9C9C gray). If alpha is not specified, full opacity is assumed." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + - name: transparent + in: query + description: Background transparency of map (default=true). + required: false + style: form + explode: false + schema: + type: boolean + default: true + - name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + type: string + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: The format of the vector tile response (e.g. json). Accepted values are 'mvt' (Mapbox Vector Tiles) or 'json' (GeoJSON). + required: false + style: form + explode: false + schema: + type: string + enum: + - mvt + - json + responses: + "200": + $ref: "#/components/responses/VectorTile" + "204": + $ref: "#/components/responses/EmptyTile" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/coverage/tiles: + get: + tags: + - Coverage Tiles + summary: Retrieve the list of available coverage tilesets for the specified collection. + operationId: .collection.coverage.getTileSetsList + parameters: + - name: collectionId + in: path + description: Local identifier of a coverage collection + required: true + style: simple + explode: false + schema: + $ref: "#/components/schemas/coverage-collections" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileSetsList" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/coverage/tiles/{tileMatrixSetId}: + get: + tags: + - Coverage Tiles + summary: Retrieve the coverage tileset metadata for the specified collection and tiling scheme (tile matrix set) + operationId: .collection.coverage.getTileSet + parameters: + - name: collectionId + in: path + description: Local identifier of a coverage collection + required: true + style: simple + explode: false + schema: + $ref: "#/components/schemas/coverage-collections" + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/coverage-collections" + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileSet" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/coverage/tiles/{tileMatrixSetId}/{tileMatrix}/{tileRow}/{tileCol}: + get: + tags: + - Coverage Tiles + summary: Retrieve coverage tiles + operationId: .collection.coverage.getTile + parameters: + - name: tileMatrix + in: path + description: |- + Identifier selecting one of the scales defined in the TileMatrixSet and representing the scaleDenominator the tile. For example, + Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15. + required: true + schema: + type: string + example: "5" + - name: tileRow + in: path + description: "Row index of the tile on the selected TileMatrix. It cannot exceed the MatrixWidth-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 10 + - name: tileCol + in: path + description: "Column index of the tile on the selected TileMatrix. It cannot exceed the MatrixHeight-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 15 + - name: datetime + in: query + description: |- + Either a date-time or an interval, half-bounded or bounded. Date and time expressions + adhere to RFC 3339. Half-bounded intervals are expressed using double-dots. + + Examples: + + * A date-time: "2018-02-12T23:20:50Z" + * A bounded interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" + * Half-bounded intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z" + + Only features that have a temporal property that intersects the value of + `datetime` are selected. + + If a feature has multiple temporal properties, it is the decision of the + server whether only a single temporal property is used to determine + the extent or all relevant temporal properties. + required: false + style: form + explode: false + schema: + type: string + - name: collectionId + in: path + description: Local identifier of a coverage collection + required: true + style: simple + explode: false + schema: + $ref: "#/components/schemas/coverage-collections" + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/coverage-collections" + - name: subset + in: query + description: | + Retrieve only part of the data by slicing or trimming along one or more axis + For trimming: {axisAbbrev}({low}:{high}) (preserves dimensionality) + An asterisk (`*`) can be used instead of {low} or {high} to indicate the minimum/maximum value. + For slicing: {axisAbbrev}({value}) (reduces dimensionality) + required: false + style: form + explode: false + schema: + type: array + items: + type: string + - name: crs + in: query + description: reproject the output to the given crs + required: false + style: form + explode: true + schema: + type: string + - name: subset-crs + in: query + description: crs for the specified subset + required: false + style: form + explode: true + schema: + type: string + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the coverage tile response (e.g. tiff). Accepted values are 'tiff' (GeoTIFF), 'netcdf', or 'png'." + required: false + style: form + explode: false + schema: + type: string + enum: + - tiff + - netcdf + - png + responses: + "200": + $ref: "#/components/responses/CoverageTile" + "204": + $ref: "#/components/responses/EmptyTile" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /map/tiles: + get: + tags: + - Map Tiles + summary: Retrieve the list of all default map tilesets for the whole dataset + operationId: .dataset.map.getTileSetsList + parameters: + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileSetsList" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /map/tiles/{tileMatrixSetId}: + get: + tags: + - Map Tiles + summary: Retrieve a default map tileset of the whole dataset for the specified tiling scheme (tile matrix set) + operationId: .dataset.map.getTileSet + parameters: + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileSet" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /map/tiles/{tileMatrixSetId}/{tileMatrix}/{tileRow}/{tileCol}: + get: + tags: + - Map Tiles + summary: Retrieve a default map tile of the whole dataset + operationId: .dataset.map.getTile + parameters: + - name: tileMatrix + in: path + description: |- + Identifier selecting one of the scales defined in the TileMatrixSet and representing the scaleDenominator the tile. For example, + Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15. + required: true + schema: + type: string + example: "5" + - name: tileRow + in: path + description: "Row index of the tile on the selected TileMatrix. It cannot exceed the MatrixWidth-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 10 + - name: tileCol + in: path + description: "Column index of the tile on the selected TileMatrix. It cannot exceed the MatrixHeight-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 15 + - name: datetime + in: query + description: |- + Either a date-time or an interval, half-bounded or bounded. Date and time expressions + adhere to RFC 3339. Half-bounded intervals are expressed using double-dots. + + Examples: + + * A date-time: "2018-02-12T23:20:50Z" + * A bounded interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" + * Half-bounded intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z" + + Only features that have a temporal property that intersects the value of + `datetime` are selected. + + If a feature has multiple temporal properties, it is the decision of the + server whether only a single temporal property is used to determine + the extent or all relevant temporal properties. + required: false + style: form + explode: false + schema: + type: string + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + - name: subset + in: query + description: | + Retrieve only part of the data by slicing or trimming along one or more axis + For trimming: {axisAbbrev}({low}:{high}) (preserves dimensionality) + An asterisk (`*`) can be used instead of {low} or {high} to indicate the minimum/maximum value. + For slicing: {axisAbbrev}({value}) (reduces dimensionality) + required: false + style: form + explode: false + schema: + type: array + items: + type: string + - name: crs + in: query + description: reproject the output to the given crs + required: false + style: form + explode: true + schema: + type: string + - name: subset-crs + in: query + description: crs for the specified subset + required: false + style: form + explode: true + schema: + type: string + - name: bgcolor + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the background color (default to 0x9C9C9C gray). If alpha is not specified, full opacity is assumed." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + - name: transparent + in: query + description: Background transparency of map (default=true). + required: false + style: form + explode: false + schema: + type: boolean + default: true + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the map tile response (e.g. png). Accepted values are 'png', 'jpg' or 'tiff' (GeoTIFF)." + required: false + style: form + explode: false + schema: + type: string + enum: + - png + - jpg + - tiff + responses: + "200": + $ref: "#/components/responses/MapTile" + "204": + $ref: "#/components/responses/EmptyTile" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /styles/{styleId}/map/tiles: + get: + tags: + - Map Tiles + summary: Retrieve the list of styled map tilesets for the whole dataset + operationId: .dataset.style.map.getTileSetsList + parameters: + - name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + $ref: "#/components/schemas/styles" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileSetsList" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /styles/{styleId}/map/tiles/{tileMatrixSetId}: + get: + tags: + - Map Tiles + summary: Retrieve a styled map tileset of the whole dataset for the specified tiling scheme (tile matrix set) + operationId: .dataset.style.map.getTileSet + parameters: + - name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + $ref: "#/components/schemas/styles" + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileSet" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /styles/{styleId}/map/tiles/{tileMatrixSetId}/{tileMatrix}/{tileRow}/{tileCol}: + get: + tags: + - Map Tiles + summary: Retrieve a styled map tiles + operationId: .dataset.style.map.getTile + parameters: + - name: tileMatrix + in: path + description: |- + Identifier selecting one of the scales defined in the TileMatrixSet and representing the scaleDenominator the tile. For example, + Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15. + required: true + schema: + type: string + example: "5" + - name: tileRow + in: path + description: "Row index of the tile on the selected TileMatrix. It cannot exceed the MatrixWidth-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 10 + - name: tileCol + in: path + description: "Column index of the tile on the selected TileMatrix. It cannot exceed the MatrixHeight-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 15 + - name: datetime + in: query + description: |- + Either a date-time or an interval, half-bounded or bounded. Date and time expressions + adhere to RFC 3339. Half-bounded intervals are expressed using double-dots. + + Examples: + + * A date-time: "2018-02-12T23:20:50Z" + * A bounded interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" + * Half-bounded intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z" + + Only features that have a temporal property that intersects the value of + `datetime` are selected. + + If a feature has multiple temporal properties, it is the decision of the + server whether only a single temporal property is used to determine + the extent or all relevant temporal properties. + required: false + style: form + explode: false + schema: + type: string + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + - name: subset + in: query + description: | + Retrieve only part of the data by slicing or trimming along one or more axis + For trimming: {axisAbbrev}({low}:{high}) (preserves dimensionality) + An asterisk (`*`) can be used instead of {low} or {high} to indicate the minimum/maximum value. + For slicing: {axisAbbrev}({value}) (reduces dimensionality) + required: false + style: form + explode: false + schema: + type: array + items: + type: string + - name: crs + in: query + description: reproject the output to the given crs + required: false + style: form + explode: true + schema: + type: string + - name: subset-crs + in: query + description: crs for the specified subset + required: false + style: form + explode: true + schema: + type: string + - name: bgcolor + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the background color (default to 0x9C9C9C gray). If alpha is not specified, full opacity is assumed." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + - name: transparent + in: query + description: Background transparency of map (default=true). + required: false + style: form + explode: false + schema: + type: boolean + default: true + - name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + $ref: "#/components/schemas/styles" + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the map tile response (e.g. png). Accepted values are 'png', 'jpg' or 'tiff' (GeoTIFF)." + required: false + style: form + explode: false + schema: + type: string + enum: + - png + - jpg + - tiff + responses: + "200": + $ref: "#/components/responses/MapTile" + "204": + $ref: "#/components/responses/EmptyTile" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/map/tiles: + get: + tags: + - Map Tiles + summary: Retrieve a list of all map tilesets for specified collection. + operationId: .collection.map.getTileSetsList + parameters: + - name: collectionId + in: path + description: Local identifier of a collection + required: true + schema: + $ref: "#/components/schemas/all-collections" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileSetsList" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/map/tiles/{tileMatrixSetId}: + get: + tags: + - Map Tiles + summary: Retrieve a map tile set metadata for the specified collection and tiling scheme (tile matrix set) + operationId: .collection.map.getTileSet + parameters: + - name: collectionId + in: path + description: Local identifier of a collection + required: true + schema: + $ref: "#/components/schemas/all-collections" + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileSet" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/map/tiles/{tileMatrixSetId}/{tileMatrix}/{tileRow}/{tileCol}: + get: + tags: + - Map Tiles + summary: Retrieve a map tile from the specified collection + operationId: .collection.map.getTile + parameters: + - name: tileMatrix + in: path + description: |- + Identifier selecting one of the scales defined in the TileMatrixSet and representing the scaleDenominator the tile. For example, + Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15. + required: true + schema: + type: string + example: "5" + - name: tileRow + in: path + description: "Row index of the tile on the selected TileMatrix. It cannot exceed the MatrixWidth-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 10 + - name: tileCol + in: path + description: "Column index of the tile on the selected TileMatrix. It cannot exceed the MatrixHeight-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 15 + - name: datetime + in: query + description: |- + Either a date-time or an interval, half-bounded or bounded. Date and time expressions + adhere to RFC 3339. Half-bounded intervals are expressed using double-dots. + + Examples: + + * A date-time: "2018-02-12T23:20:50Z" + * A bounded interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" + * Half-bounded intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z" + + Only features that have a temporal property that intersects the value of + `datetime` are selected. + + If a feature has multiple temporal properties, it is the decision of the + server whether only a single temporal property is used to determine + the extent or all relevant temporal properties. + required: false + style: form + explode: false + schema: + type: string + - name: collectionId + in: path + description: Local identifier of a collection + required: true + schema: + $ref: "#/components/schemas/all-collections" + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + - name: subset + in: query + description: | + Retrieve only part of the data by slicing or trimming along one or more axis + For trimming: {axisAbbrev}({low}:{high}) (preserves dimensionality) + An asterisk (`*`) can be used instead of {low} or {high} to indicate the minimum/maximum value. + For slicing: {axisAbbrev}({value}) (reduces dimensionality) + required: false + style: form + explode: false + schema: + type: array + items: + type: string + - name: crs + in: query + description: reproject the output to the given crs + required: false + style: form + explode: true + schema: + type: string + - name: subset-crs + in: query + description: crs for the specified subset + required: false + style: form + explode: true + schema: + type: string + - name: bgcolor + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the background color (default to 0x9C9C9C gray). If alpha is not specified, full opacity is assumed." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + - name: transparent + in: query + description: Background transparency of map (default=true). + required: false + style: form + explode: false + schema: + type: boolean + default: true + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the map tile response (e.g. png). Accepted values are 'png', 'jpg' or 'tiff' (GeoTIFF)." + required: false + style: form + explode: false + schema: + type: string + enum: + - png + - jpg + - tiff + responses: + "200": + $ref: "#/components/responses/MapTile" + "204": + $ref: "#/components/responses/EmptyTile" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/styles/{styleId}/map/tiles: + get: + tags: + - Map Tiles + summary: Retrieve a list of styled map tilesets for the specified collection + operationId: .collection.style.map.getTileSetsList + parameters: + - name: collectionId + in: path + description: Local identifier of a collection + required: true + schema: + $ref: "#/components/schemas/all-collections" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + - name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + type: string + responses: + "200": + $ref: "#/components/responses/TileSetsList" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/styles/{styleId}/map/tiles/{tileMatrixSetId}: + get: + tags: + - Map Tiles + summary: "Retrieve the map tileset metadata for the specified collection, style and tiling scheme (tile matrix set)." + operationId: .collection.style.map.getTileSet + parameters: + - name: collectionId + in: path + description: Local identifier of a collection + required: true + schema: + $ref: "#/components/schemas/all-collections" + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + - name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + type: string + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + responses: + "200": + $ref: "#/components/responses/TileSet" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/styles/{styleId}/map/tiles/{tileMatrixSetId}/{tileMatrix}/{tileRow}/{tileCol}: + get: + tags: + - Map Tiles + summary: Retrieve a map tile for a specified collection and style + operationId: .collection.style.map.getTile + parameters: + - name: tileMatrix + in: path + description: |- + Identifier selecting one of the scales defined in the TileMatrixSet and representing the scaleDenominator the tile. For example, + Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15. + required: true + schema: + type: string + example: "5" + - name: tileRow + in: path + description: "Row index of the tile on the selected TileMatrix. It cannot exceed the MatrixWidth-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 10 + - name: tileCol + in: path + description: "Column index of the tile on the selected TileMatrix. It cannot exceed the MatrixHeight-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 15 + - name: datetime + in: query + description: |- + Either a date-time or an interval, half-bounded or bounded. Date and time expressions + adhere to RFC 3339. Half-bounded intervals are expressed using double-dots. + + Examples: + + * A date-time: "2018-02-12T23:20:50Z" + * A bounded interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" + * Half-bounded intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z" + + Only features that have a temporal property that intersects the value of + `datetime` are selected. + + If a feature has multiple temporal properties, it is the decision of the + server whether only a single temporal property is used to determine + the extent or all relevant temporal properties. + required: false + style: form + explode: false + schema: + type: string + - name: collectionId + in: path + description: Local identifier of a collection + required: true + schema: + $ref: "#/components/schemas/all-collections" + - name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + - name: subset + in: query + description: | + Retrieve only part of the data by slicing or trimming along one or more axis + For trimming: {axisAbbrev}({low}:{high}) (preserves dimensionality) + An asterisk (`*`) can be used instead of {low} or {high} to indicate the minimum/maximum value. + For slicing: {axisAbbrev}({value}) (reduces dimensionality) + required: false + style: form + explode: false + schema: + type: array + items: + type: string + - name: crs + in: query + description: reproject the output to the given crs + required: false + style: form + explode: true + schema: + type: string + - name: subset-crs + in: query + description: crs for the specified subset + required: false + style: form + explode: true + schema: + type: string + - name: bgcolor + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the background color (default to 0x9C9C9C gray). If alpha is not specified, full opacity is assumed." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + - name: transparent + in: query + description: Background transparency of map (default=true). + required: false + style: form + explode: false + schema: + type: boolean + default: true + - name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + type: string + - name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + - name: f + in: query + description: "The format of the map tile response (e.g. png). Accepted values are 'png', 'jpg' or 'tiff' (GeoTIFF)." + required: false + style: form + explode: false + schema: + type: string + enum: + - png + - jpg + - tiff + responses: + "200": + $ref: "#/components/responses/MapTile" + "204": + $ref: "#/components/responses/EmptyTile" + "404": + $ref: "#/components/responses/NotFound" + "406": + $ref: "#/components/responses/NotAcceptable" + "500": + $ref: "#/components/responses/ServerError" +components: + schemas: + confClasses: + required: + - conformsTo + type: object + properties: + conformsTo: + type: array + items: + type: string + link: + required: + - href + - rel + type: object + properties: + href: + type: string + description: Supplies the URI to a remote resource (or resource fragment). + example: http://data.example.com/buildings/123 + rel: + type: string + description: The type or semantics of the relation. + example: alternate + type: + type: string + description: A hint indicating what the media type of the result of dereferencing the link should be. + example: application/geo+json + templated: + type: boolean + description: This flag set to true if the link is a URL template. + varBase: + type: string + description: A base path to retrieve semantic information about the variables used in URL template. + example: /ogcapi/vars/ + hreflang: + type: string + description: A hint indicating what the language of the result of dereferencing the link should be. + example: en + title: + type: string + description: Used to label the destination of a link such that it can be used as a human-readable identifier. + example: "Trierer Strasse 70, 53115 Bonn" + length: + type: integer + landingPage: + required: + - links + type: object + properties: + title: + title: The title of the API. + type: string + description: "While a title is not required, implementors are strongly advised to include one." + example: Buildings in Bonn + description: + type: string + example: Access to data about buildings in the city of Bonn via a Web API that conforms to the OGC API Common specification. + attribution: + title: attribution for the API + type: string + description: "The `attribution` should be short and intended for presentation to a user, for example, in a corner of a map. Parts of the text can be links to other resources if additional information is needed. The string can include HTML markup." + links: + type: array + items: + $ref: "#/components/schemas/link" + exception: + title: Exception Schema + required: + - type + type: object + properties: + type: + type: string + title: + type: string + status: + type: integer + detail: + type: string + instance: + type: string + description: JSON schema for exceptions based on RFC 7807 + collections: + required: + - collections + - links + type: object + properties: + links: + type: array + items: + $ref: "#/components/schemas/link" + timeStamp: + type: string + format: date-time + numberMatched: + minimum: 0 + type: integer + example: 1 + numberReturned: + minimum: 0 + type: integer + example: 1 + collections: + type: array + items: + $ref: "#/components/schemas/collectionInfo" + collectionInfo: + required: + - id + - links + type: object + properties: + id: + type: string + description: "identifier of the collection used, for example, in URIs" + example: dem + title: + type: string + description: human readable title of the collection + example: Digital Elevation Model + description: + type: string + description: a description of the data in the collection + example: A Digital Elevation Model. + links: + type: array + example: + - href: http://data.example.org/collections/dem?f=json + rel: self + type: application/json + title: Digital Elevation Model + - href: http://data.example.org/collections/dem?f=html + rel: alternate + type: application/json + title: Digital Elevation Model + - href: http://data.example.org/collections/dem/coverage + rel: coverage + type: image/tiff; application=geotiff + title: Digital Elevation Model + - href: http://data.example.org/collections/dem/coverage/domainset + rel: domainset + type: application/json + title: Digital Elevation Model + - href: http://data.example.org/collections/dem/coverage/rangetype + rel: rangetype + type: application/json + title: Digital Elevation Model + - href: http://data.example.org/collections/dem/coverage/metadata + rel: metadata + type: application/json + title: Digital Elevation Model + items: + $ref: "#/components/schemas/link" + extent: + $ref: "#/components/schemas/extent-uad" + itemType: + type: string + description: "indicator about the type of the items in the collection if the collection has an accessible /collections/{collectionId}/items endpoint" + default: unknown + crs: + type: array + description: the list of coordinate reference systems supported by the API; the first item is the default coordinate reference system + example: + - http://www.opengis.net/def/crs/OGC/1.3/CRS84 + - http://www.opengis.net/def/crs/EPSG/0/4326 + items: + type: string + default: + - http://www.opengis.net/def/crs/OGC/1.3/CRS84 + dataType: + allOf: + - description: Type of data represented in the collection + - $ref: "#/components/schemas/dataType" + geometryDimension: + maximum: 3 + minimum: 0 + type: integer + description: "The geometry dimension of the features shown in this layer (0: points, 1: curves, 2: surfaces, 3: solids), unspecified: mixed or unknown" + minScaleDenominator: + type: number + description: Minimum scale denominator for usage of the collection + maxScaleDenominator: + type: number + description: Maximum scale denominator for usage of the collection + minCellSize: + type: number + description: Minimum cell size for usage of the collection + maxCellSize: + type: number + description: Maximum cell size for usage of the collection + extent: + type: object + properties: + spatial: + $ref: "#/components/schemas/extent_spatial" + temporal: + $ref: "#/components/schemas/extent_temporal" + description: |- + The extent of the data in the collection. In the Core only spatial and temporal + extents are specified. Extensions may add additional members to represent other + extents, for example, thermal or pressure ranges. + + The first item in the array describes the overall extent of + the data. All subsequent items describe more precise extents, + e.g., to identify clusters of data. + Clients only interested in the overall extent will only need to + access the first item in each array. + extent-uad: + title: Extent with Uniform Additional Dimensions Schema + description: |- + The extent module only addresses spatial and temporal extents. This module extends extent by specifying how + intervals and crs properties can be used to specify additional geometries. + allOf: + - $ref: "#/components/schemas/extent" + - type: object + additionalProperties: + type: object + properties: + interval: + minItems: 1 + type: array + description: |- + One or more intervals that describe the extent for this dimension of the dataset. + The value `null` is supported and indicates an unbounded or half-bounded interval. + The first interval describes the overall extent of the data for this dimension. + All subsequent intervals describe more precise intervals, e.g., to identify clusters of data. + Clients only interested in the overall extent will only need + to access the first item (a pair of lower and upper bound values). + items: + maxItems: 2 + minItems: 2 + type: array + description: |- + Lower and upper bound values of the interval. The values + are in the coordinate reference system specified in `crs`, `trs` or `vrs`. + example: + - 2011-11-11T12:22:11Z + - 32.5 + - null + items: + oneOf: + - type: string + nullable: true + - type: number + crs: + type: string + description: generic coordinate reference system suitable for any type of dimensions + trs: + type: string + description: temporal coordinate reference system (e.g. as defined by Features for 'temporal') + vrs: + type: string + description: vertical coordinate reference system (e.g. as defined in EDR for 'vertical') + grid: + type: object + properties: + coordinates: + minItems: 1 + type: array + description: |- + List of coordinates along the temporal dimension for which data organized as an irregular grid in the collection is available + (e.g., 2, 10, 80, 100). + example: + - 2 + - 10 + - 80 + - 100 + items: + oneOf: + - type: string + nullable: true + - type: number + cellsCount: + type: integer + description: |- + Number of samples available along the dimension for data organized as a regular grid. + For values representing the whole area of contiguous cells spanning _resolution_ units along the dimension, this will be (_upperBound_ - _lowerBound_) / _resolution_. + For values representing infinitely small point cells spaced by _resolution_ units along the dimension, this will be (_upperBound_ - _lowerBound_) / _resolution_ + 1. + example: 50 + resolution: + description: Resolution of regularly gridded data along the dimension in the collection + example: + - PT1H + - 0.0006866455078 + oneOf: + - type: string + nullable: true + - type: number + description: Provides information about the limited availability of data within the collection organized as a grid (regular or irregular) along the dimension. + description: The domain intervals for any additional dimensions of the extent (envelope) beyond those described in temporal and spatial. + oneOf: + - required: + - crs + - interval + - required: + - interval + - trs + - required: + - interval + - vrs + crs: + title: CRS + oneOf: + - type: string + description: Simplification of the object into a url if the other properties are not present + - type: object + oneOf: + - required: + - uri + properties: + uri: + type: string + description: Reference to one coordinate reference system (CRS) + format: uri + - required: + - wkt + properties: + wkt: + allOf: + - description: An object defining the CRS using the JSON encoding for Well-known text representation of coordinate reference systems 2.0 + - type: object + - required: + - referenceSystem + properties: + referenceSystem: + type: object + description: A reference system data structure as defined in the MD_ReferenceSystem of the ISO 19115 + dataType: + oneOf: + - type: string + - type: string + enum: + - map + - vector + - coverage + timeStamp: + type: string + description: This property indicates the time and date when the response was generated using RFC 3339 notation. + format: date-time + example: 2017-08-17T08:05:32Z + numberReturned: + minimum: 0 + type: integer + description: |- + The number of features in the feature collection. + A server may omit this information in a response, if the information + about the number of features is not known or difficult to compute. + If the value is provided, the value shall be identical to the number + of items in the "features" array. + example: 10 + numberMatched: + minimum: 0 + type: integer + description: |- + The number of features of the feature type that match the selection + parameters like `bbox`. + example: 127 + tileSet: + title: Tile Set Metadata + required: + - crs + - dataType + - links + type: object + properties: + title: + type: string + description: A title for this tileset + description: + type: string + description: Brief narrative description of this tile set + dataType: + allOf: + - description: Type of data represented in the tileset + - $ref: "#/components/schemas/dataType" + crs: + allOf: + - description: Coordinate Reference System (CRS) + - $ref: "#/components/schemas/crs" + tileMatrixSetURI: + type: string + description: Reference to a Tile Matrix Set on an offical source for Tile Matrix Sets such as the OGC NA definition server (http://www.opengis.net/def/tms/). Required if the tile matrix set is registered on an open official source. + format: uri + links: + type: array + description: "Links to related resources. Possible link 'rel' values are: 'http://www.opengis.net/def/rel/ogc/1.0/dataset' for a URL pointing to the dataset, 'item' for a URL template to get a tile; 'alternate' for a URL pointing to another representation of the TileSetMetadata (e.g a TileJSON file); 'http://www.opengis.net/def/rel/ogc/1.0/tiling-scheme' for a definition of the TileMatrixSet; 'http://www.opengis.net/def/rel/ogc/1.0/geodata' for pointing to a single collection (if the tileset represents a single collection)" + items: + $ref: "#/components/schemas/link" + tileMatrixSetLimits: + type: array + description: "Limits for the TileRow and TileCol values for each TileMatrix in the tileMatrixSet. If missing, there are no limits other that the ones imposed by the TileMatrixSet. If present the TileMatrices listed are limited and the rest not available at all" + items: + $ref: "#/components/schemas/tileMatrixLimits" + epoch: + type: number + description: Epoch of the Coordinate Reference System (CRS) + layers: + minItems: 1 + type: array + items: + $ref: "#/components/schemas/tileSet_layers" + boundingBox: + allOf: + - description: "Minimum bounding rectangle surrounding the tile matrix set, in the supported CRS" + - $ref: "#/components/schemas/2DBoundingBox" + centerPoint: + allOf: + - description: Location of a tile that nicely represents the tileset. Implementations may use this center value to set the default location or to present a representative tile in a user interface + - required: + - coordinates + type: object + properties: + coordinates: + maxItems: 2 + minItems: 2 + type: array + items: + type: number + crs: + allOf: + - description: Coordinate Reference System (CRS) of the coordinates + - $ref: "#/components/schemas/crs" + tileMatrix: + type: string + description: TileMatrix identifier associated with the scaleDenominator + scaleDenominator: + type: number + description: Scale denominator of the tile matrix selected + cellSize: + type: number + description: Cell size of the tile matrix selected + style: + allOf: + - description: Style involving all layers used to generate the tileset + - required: + - id + type: object + properties: + id: + type: string + description: An identifier for this style. Implementation of 'identifier' + title: + type: string + description: A title for this style + description: + type: string + description: Brief narrative description of this style + keywords: + type: array + description: keywords about this style + items: + type: string + links: + minItems: 1 + type: array + description: "Links to style related resources. Possible link 'rel' values are: 'style' for a URL pointing to the style description, 'styleSpec' for a URL pointing to the specification or standard used to define the style." + items: + $ref: "#/components/schemas/link" + attribution: + type: string + description: Short reference to recognize the author or provider + license: + type: string + description: License applicable to the tiles + accessConstraints: + type: string + description: Restrictions on the availability of the Tile Set that the user needs to be aware of before using or redistributing the Tile Set + enum: + - unclassified + - restricted + - confidential + - secret + - topSecret + default: unclassified + keywords: + type: array + description: keywords about this tileset + items: + type: string + version: + type: string + description: Version of the Tile Set. Changes if the data behind the tiles has been changed + created: + allOf: + - description: When the Tile Set was first produced + - $ref: "#/components/schemas/timeStamp" + updated: + allOf: + - description: Last Tile Set change/revision + - $ref: "#/components/schemas/timeStamp" + pointOfContact: + type: string + description: Useful information to contact the authors or custodians for the Tile Set + mediaTypes: + type: array + description: Media types available for the tiles + items: + type: string + description: "A resource describing a tileset based on the OGC TileSet Metadata Standard. At least one of the 'TileMatrixSet', or a link with 'rel' http://www.opengis.net/def/rel/ogc/1.0/tiling-scheme" + tileSet-item: + title: Tile Set Metadata item + required: + - crs + - dataType + - links + type: object + properties: + title: + type: string + description: A title for this tileset + dataType: + allOf: + - description: Type of data represented in the tileset + - $ref: "#/components/schemas/dataType" + crs: + allOf: + - description: Coordinate Reference System (CRS) + - $ref: "#/components/schemas/crs" + tileMatrixSetURI: + type: string + description: Reference to a Tile Matrix Set on an offical source for Tile Matrix Sets such as the OGC NA definition server (http://www.opengis.net/def/tms/). Required if the tile matrix set is registered on an open official source. + format: uri + links: + type: array + description: Links to related resources. A 'self' link to the tileset as well as a 'http://www.opengis.net/def/rel/ogc/1.0/tiling-scheme' link to a definition of the TileMatrixSet are required. + items: + $ref: "#/components/schemas/link" + description: A minimal tileset element for use within a list of tilesets linking to full description of those tilesets. + tileMatrixSet: + title: Tile Matrix Set Definition + required: + - crs + - tileMatrices + type: object + properties: + title: + type: string + description: "Title of this tile matrix set, normally used for display to a human" + description: + type: string + description: "Brief narrative description of this tile matrix set, normally available for display to a human" + keywords: + type: array + description: Unordered list of one or more commonly used or formalized word(s) or phrase(s) used to describe this tile matrix set + items: + type: string + id: + type: string + description: Tile matrix set identifier. Implementation of 'identifier' + uri: + type: string + description: Reference to an official source for this tileMatrixSet + format: uri + orderedAxes: + minItems: 1 + type: array + items: + type: string + crs: + allOf: + - description: Coordinate Reference System (CRS) + - $ref: "#/components/schemas/crs" + wellKnownScaleSet: + type: string + description: Reference to a well-known scale set + format: uri + boundingBox: + allOf: + - description: "Minimum bounding rectangle surrounding the tile matrix set, in the supported CRS" + - $ref: "#/components/schemas/2DBoundingBox" + tileMatrices: + type: array + description: Describes scale levels and its tile matrices + items: + $ref: "#/components/schemas/tileMatrixSet_tileMatrices" + description: "A definition of a tile matrix set following the Tile Matrix Set standard. For tileset metadata, such a description (in `tileMatrixSet` property) is only required for offline use, as an alternative to a link with a `http://www.opengis.net/def/rel/ogc/1.0/tiling-scheme` relation type." + tileMatrixSet-item: + title: Tile Matrix Set Item + required: + - links + type: object + properties: + id: + type: string + description: "Optional local tile matrix set identifier, e.g. for use as unspecified `{tileMatrixSetId}` parameter. Implementation of 'identifier'" + title: + type: string + description: "Title of this tile matrix set, normally used for display to a human" + uri: + type: string + description: Reference to an official source for this tileMatrixSet + format: uri + crs: + allOf: + - description: Coordinate Reference System (CRS) + - $ref: "#/components/schemas/crs" + links: + type: array + description: Links to related resources. A 'self' link to the tile matrix set definition is required. + items: + $ref: "#/components/schemas/link" + description: A minimal tile matrix set element for use within a list of tile matrix sets linking to a full definition. + tileMatrixLimits: + title: TileMatrixLimits + required: + - maxTileCol + - maxTileRow + - minTileCol + - minTileRow + - tileMatrix + type: object + properties: + tileMatrix: + type: string + minTileRow: + minimum: 0 + type: integer + maxTileRow: + minimum: 0 + type: integer + minTileCol: + minimum: 0 + type: integer + maxTileCol: + minimum: 0 + type: integer + description: "The limits for an individual tile matrix of a TileSet's TileMatrixSet, as defined in the OGC 2D TileMatrixSet and TileSet Metadata Standard" + "2DPoint": + maxItems: 2 + minItems: 2 + type: array + description: A 2D Point in the CRS indicated elsewhere + items: + type: number + "2DBoundingBox": + required: + - lowerLeft + - upperRight + type: object + properties: + lowerLeft: + $ref: "#/components/schemas/2DPoint" + upperRight: + $ref: "#/components/schemas/2DPoint" + crs: + $ref: "#/components/schemas/crs" + orderedAxes: + maxItems: 2 + minItems: 2 + type: array + items: + type: string + description: Minimum bounding rectangle surrounding a 2D resource in the CRS indicated elsewhere + FeatureCollection: + title: GeoJSON FeatureCollection + required: + - features + - type + type: object + properties: + type: + type: string + enum: + - FeatureCollection + features: + type: array + items: + $ref: "#/components/schemas/GeoJSON Feature" + bbox: + minItems: 4 + type: array + items: + type: number + enumeration: + required: + - enum + - type + type: object + properties: + type: + type: string + enum: + - enum + enum: + type: array + items: + type: string + all-collections: + type: string + enum: + - blueMarble + - NaturalEarth:raster:HYP_HR_SR_OB_DR + - NaturalEarth:cultural:ne_10m_admin_0_countries + - NaturalEarth:physical:bathymetry + - SRTM_ViewFinderPanorama + - HRDEM-Ottawa + - HRDEM-RedRiver + vectorTiles-collections: + type: string + enum: + - NaturalEarth:cultural:ne_10m_admin_0_countries + - NaturalEarth:physical:bathymetry + coverage-collections: + type: string + enum: + - SRTM_ViewFinderPanorama + - HRDEM-Ottawa + - HRDEM-RedRiver + styles: + type: string + enum: + - default + tileMatrixSets: + type: string + enum: + - WebMercatorQuad + - WorldCRS84Quad + - GNOSISGlobalGrid + - WorldMercatorWGS84Quad + extent_spatial_grid: + type: object + properties: + coordinates: + minItems: 1 + type: array + description: |- + List of coordinates along the dimension for which data organized as an irregular grid in the collection is available + (e.g., 2, 10, 80, 100). + example: + - 2 + - 10 + - 80 + - 100 + items: + oneOf: + - type: string + nullable: true + - type: number + cellsCount: + type: integer + description: |- + Number of samples available along the dimension for data organized as a regular grid. + For values representing the whole area of contiguous cells spanning _resolution_ units along the dimension, this will be (_upperBound_ - _lowerBound_) / _resolution_. + For values representing infinitely small point cells spaced by _resolution_ units along the dimension, this will be (_upperBound_ - _lowerBound_) / _resolution_ + 1. + example: 50 + resolution: + description: Resolution of regularly gridded data along the dimension in the collection + example: 0.0006866455078 + oneOf: + - type: string + nullable: true + - type: number + extent_spatial: + type: object + properties: + bbox: + minItems: 1 + type: array + description: |- + One or more bounding boxes that describe the spatial extent of the dataset. + In the Core only a single bounding box is supported. + + Extensions may support additional areas. + The first bounding box describes the overall spatial + extent of the data. All subsequent bounding boxes describe + more precise bounding boxes, e.g., to identify clusters of data. + Clients only interested in the overall spatial extent will + only need to access the first item in each array. + items: + type: array + description: |- + Each bounding box is provided as four or six numbers, depending on + whether the coordinate reference system includes a vertical axis + (height or depth): + + * Lower left corner, coordinate axis 1 + * Lower left corner, coordinate axis 2 + * Minimum value, coordinate axis 3 (optional) + * Upper right corner, coordinate axis 1 + * Upper right corner, coordinate axis 2 + * Maximum value, coordinate axis 3 (optional) + + If the value consists of four numbers, the coordinate reference system is + WGS 84 longitude/latitude (http://www.opengis.net/def/crs/OGC/1.3/CRS84) + unless a different coordinate reference system is specified in a parameter `bbox-crs`. + + If the value consists of six numbers, the coordinate reference system is WGS 84 + longitude/latitude/ellipsoidal height (http://www.opengis.net/def/crs/OGC/0/CRS84h) + unless a different coordinate reference system is specified in a parameter `bbox-crs`. + + For WGS 84 longitude/latitude the values are in most cases the sequence of + minimum longitude, minimum latitude, maximum longitude and maximum latitude. + However, in cases where the box spans the antimeridian the first value + (west-most box edge) is larger than the third value (east-most box edge). + + If the vertical axis is included, the third and the sixth number are + the bottom and the top of the 3-dimensional bounding box. + + If a feature has multiple spatial geometry properties, it is the decision of the + server whether only a single spatial geometry property is used to determine + the extent or all relevant geometries. + example: + - -180 + - -90 + - 180 + - 90 + items: + type: number + crs: + type: string + description: |- + Coordinate reference system of the coordinates in the spatial extent + (property `bbox`). The default reference system is WGS 84 longitude/latitude. + In the Core the only other supported coordinate reference system is + WGS 84 longitude/latitude/ellipsoidal height for coordinates with height. + Extensions may support additional coordinate reference systems and add + additional enum values. + enum: + - http://www.opengis.net/def/crs/OGC/1.3/CRS84 + - http://www.opengis.net/def/crs/OGC/0/CRS84h + default: http://www.opengis.net/def/crs/OGC/1.3/CRS84 + grid: + maxItems: 3 + minItems: 2 + type: array + description: |- + Provides information about the limited availability of data within the collection organized + as a grid (regular or irregular) along each spatial dimension. + items: + $ref: "#/components/schemas/extent_spatial_grid" + description: The spatial extent of the data in the collection. + extent_temporal_grid: + type: object + properties: + coordinates: + minItems: 1 + type: array + description: |- + List of coordinates along the temporal dimension for which data organized as an irregular grid in the collection is available + (e.g., "2017-11-14T09:00Z","2017-11-14T12:00Z","2017-11-14T15:00Z","2017-11-14T18:00Z","2017-11-14T21:00Z"). + example: + - - 2020-11-12T12:15Z + - 2020-11-12T12:30Z + - 2020-11-12T12:45Z + items: + type: string + nullable: true + cellsCount: + type: integer + description: |- + Number of samples available along the temporal dimension for data organized as a regular grid. + For values representing the whole area of contiguous cells spanning _resolution_ units along the dimension, this will be (_upperBound_ - _lowerBound_) / _resolution_. + For values representing infinitely small point cells spaced by _resolution_ units along the dimension, this will be (_upperBound_ - _lowerBound_) / _resolution_ + 1. + example: 50 + resolution: + description: Resolution of regularly gridded data along the temporal dimension in the collection + example: PT1H + oneOf: + - type: string + nullable: true + - type: number + description: Provides information about the limited availability of data within the collection organized as a grid (regular or irregular) along the temporal dimension. + extent_temporal: + type: object + properties: + interval: + minItems: 1 + type: array + description: |- + One or more time intervals that describe the temporal extent of the dataset. + In the Core only a single time interval is supported. + + Extensions may support multiple intervals. + The first time interval describes the overall + temporal extent of the data. All subsequent time intervals describe + more precise time intervals, e.g., to identify clusters of data. + Clients only interested in the overall extent will only need + to access the first item in each array. + items: + maxItems: 2 + minItems: 2 + type: array + description: |- + Begin and end times of the time interval. The timestamps are in the + temporal coordinate reference system specified in `trs`. By default + this is the Gregorian calendar. + + The value `null` for start or end time is supported and indicates a half-bounded time interval. + example: + - 2011-11-11T12:22:11Z + - null + items: + type: string + format: date-time + nullable: true + trs: + type: string + description: |- + Coordinate reference system of the coordinates in the temporal extent + (property `interval`). The default reference system is the Gregorian calendar. + In the Core this is the only supported temporal coordinate reference system. + Extensions may support additional temporal coordinate reference systems and add + additional enum values. + enum: + - http://www.opengis.net/def/uom/ISO-8601/0/Gregorian + default: http://www.opengis.net/def/uom/ISO-8601/0/Gregorian + grid: + $ref: "#/components/schemas/extent_temporal_grid" + description: The temporal extent of the features in the collection. + tileSet_layers: + required: + - dataType + - id + type: object + properties: + title: + type: string + description: "Title of this tile matrix set, normally used for display to a human" + description: + type: string + description: "Brief narrative description of this tile matrix set, normally available for display to a human" + keywords: + type: string + description: Unordered list of one or more commonly used or formalized word(s) or phrase(s) used to describe this layer + id: + type: string + description: Unique identifier of the Layer. Implementation of 'identifier' + dataType: + allOf: + - description: Type of data represented in the layer + - $ref: "#/components/schemas/dataType" + geometryDimension: + maximum: 3 + minimum: 0 + type: integer + description: "The geometry dimension of the features shown in this layer (0: points, 1: curves, 2: surfaces, 3: solids), unspecified: mixed or unknown" + featureType: + type: string + description: Feature type identifier. Only applicable to layers of datatype 'geometries' + attribution: + type: string + description: Short reference to recognize the author or provider + license: + type: string + description: License applicable to the tiles + pointOfContact: + type: string + description: "Useful information to contact the authors or custodians for the layer (e.g. e-mail address, a physical address, phone numbers, etc)" + publisher: + type: string + description: Organization or individual responsible for making the layer available + theme: + type: string + description: Category where the layer can be grouped + crs: + allOf: + - description: Coordinate Reference System (CRS) + - $ref: "#/components/schemas/crs" + epoch: + type: number + description: Epoch of the Coordinate Reference System (CRS) + minScaleDenominator: + type: number + description: Minimum scale denominator for usage of the layer + maxScaleDenominator: + type: number + description: Maximum scale denominator for usage of the layer + minCellSize: + type: number + description: Minimum cell size for usage of the layer + maxCellSize: + type: number + description: Maximum cell size for usage of the layer + maxTileMatrix: + type: string + description: TileMatrix identifier associated with the minScaleDenominator + minTileMatrix: + type: string + description: TileMatrix identifier associated with the maxScaleDenominator + boundingBox: + allOf: + - description: Minimum bounding rectangle surrounding the layer + - $ref: "#/components/schemas/2DBoundingBox" + created: + allOf: + - description: When the layer was first produced + - $ref: "#/components/schemas/timeStamp" + updated: + allOf: + - description: Last layer change/revision + - $ref: "#/components/schemas/timeStamp" + style: + allOf: + - description: Style used to generate the layer in the tileset + - $ref: "#/components/schemas/tileSet/properties/style/allOf/1" + geoDataClasses: + type: array + description: URI identifying a class of data contained in this layer (useful to determine compatibility with styles or processes) + items: + type: string + propertiesSchema: + allOf: + - description: Properties represented by the features in this layer. Can be the attributes of a feature dataset (datatype=geometries) or the rangeType of a coverage (datatype=coverage) + - required: + - properties + - type + type: object + properties: + type: + type: string + enum: + - object + required: + minItems: 1 + type: array + description: Implements 'multiplicity' by citing property 'name' defined as 'additionalProperties' + items: + type: string + properties: + type: object + additionalProperties: + type: object + properties: + title: + type: string + description: + type: string + description: Implements 'description' + type: + type: string + enum: + - array + - boolean + - integer + - "null" + - number + - object + - string + enum: + minItems: 1 + uniqueItems: true + type: array + description: Implements 'acceptedValues' + items: {} + format: + type: string + description: Complements implementation of 'type' + contentMediaType: + type: string + description: Implements 'mediaType' + maximum: + type: number + description: Implements 'range' + exclusiveMaximum: + type: number + description: Implements 'range' + minimum: + type: number + description: Implements 'range' + exclusiveMinimum: + type: number + description: Implements 'range' + pattern: + type: string + format: regex + maxItems: + minimum: 0 + type: integer + description: Implements 'upperMultiplicity' + minItems: + minimum: 0 + type: integer + description: Implements 'lowerMultiplicity' + default: 0 + observedProperty: + type: string + observedPropertyURI: + type: string + format: uri + uom: + type: string + uomURI: + type: string + format: uri + description: No property names are defined but any property name they should be described by JSON Schema. So 'additionalProperties' implements 'name'. + default: {} + description: Attributes of the features or rangetypes of a coverage. Defined by a subset of the JSON Schema for the properties of a feature + links: + minItems: 1 + type: array + description: "Links related to this layer. Possible link 'rel' values are: 'geodata' for a URL pointing to the collection of geospatial data." + items: + $ref: "#/components/schemas/link" + tileMatrixSet_variableMatrixWidths: + required: + - coalesce + - maxTileRow + - minTileRow + type: object + properties: + coalesce: + multipleOf: 1 + minimum: 2 + type: number + description: Number of tiles in width that coalesce in a single tile for these rows + format: integer + minTileRow: + multipleOf: 1 + minimum: 0 + type: number + description: First tile row where the coalescence factor applies for this tilematrix + format: integer + maxTileRow: + multipleOf: 1 + minimum: 0 + type: number + description: Last tile row where the coalescence factor applies for this tilematrix + format: integer + description: Variable Matrix Width data structure + tileMatrixSet_tileMatrices: + required: + - cellSize + - id + - matrixHeight + - matrixWidth + - pointOfOrigin + - scaleDenominator + - tileHeight + - tileWidth + type: object + properties: + title: + type: string + description: "Title of this tile matrix, normally used for display to a human" + description: + type: string + description: "Brief narrative description of this tile matrix set, normally available for display to a human" + keywords: + type: array + description: Unordered list of one or more commonly used or formalized word(s) or phrase(s) used to describe this dataset + items: + type: string + id: + type: string + description: Identifier selecting one of the scales defined in the TileMatrixSet and representing the scaleDenominator the tile. Implementation of 'identifier' + scaleDenominator: + type: number + description: Scale denominator of this tile matrix + cellSize: + type: number + description: Cell size of this tile matrix + cornerOfOrigin: + type: string + description: "The corner of the tile matrix (_topLeft_ or _bottomLeft_) used as the origin for numbering tile rows and columns. This corner is also a corner of the (0, 0) tile." + enum: + - topLeft + - bottomLeft + default: topLeft + pointOfOrigin: + allOf: + - description: "Precise position in CRS coordinates of the corner of origin (e.g. the top-left corner) for this tile matrix. This position is also a corner of the (0, 0) tile. In previous version, this was 'topLeftCorner' and 'cornerOfOrigin' did not exist." + - $ref: "#/components/schemas/2DPoint" + tileWidth: + multipleOf: 1 + minimum: 1 + type: number + description: Width of each tile of this tile matrix in pixels + format: integer + tileHeight: + multipleOf: 1 + minimum: 1 + type: number + description: Height of each tile of this tile matrix in pixels + format: integer + matrixHeight: + multipleOf: 1 + minimum: 1 + type: number + description: Width of the matrix (number of tiles in width) + format: integer + matrixWidth: + multipleOf: 1 + minimum: 1 + type: number + description: Height of the matrix (number of tiles in height) + format: integer + variableMatrixWidths: + type: array + description: Describes the rows that has variable matrix width + items: + $ref: "#/components/schemas/tileMatrixSet_variableMatrixWidths" + description: "A tile matrix, usually corresponding to a particular zoom level of a TileMatrixSet." + GeoJSON Feature: + title: GeoJSON Feature + required: + - geometry + - properties + - type + type: object + properties: + type: + type: string + enum: + - Feature + id: + oneOf: + - type: number + - type: string + properties: + type: object + nullable: true + geometry: + oneOf: + - title: GeoJSON Point + required: + - coordinates + - type + type: object + properties: + type: + type: string + enum: + - Point + coordinates: + minItems: 2 + type: array + items: + type: number + bbox: + minItems: 4 + type: array + items: + type: number + nullable: true + - title: GeoJSON LineString + required: + - coordinates + - type + type: object + properties: + type: + type: string + enum: + - LineString + coordinates: + minItems: 2 + type: array + items: + minItems: 2 + type: array + items: + type: number + bbox: + minItems: 4 + type: array + items: + type: number + - title: GeoJSON Polygon + required: + - coordinates + - type + type: object + properties: + type: + type: string + enum: + - Polygon + coordinates: + type: array + items: + minItems: 4 + type: array + items: + minItems: 2 + type: array + items: + type: number + bbox: + minItems: 4 + type: array + items: + type: number + - title: GeoJSON MultiPoint + required: + - coordinates + - type + type: object + properties: + type: + type: string + enum: + - MultiPoint + coordinates: + type: array + items: + minItems: 2 + type: array + items: + type: number + bbox: + minItems: 4 + type: array + items: + type: number + - title: GeoJSON MultiLineString + required: + - coordinates + - type + type: object + properties: + type: + type: string + enum: + - MultiLineString + coordinates: + type: array + items: + minItems: 2 + type: array + items: + minItems: 2 + type: array + items: + type: number + bbox: + minItems: 4 + type: array + items: + type: number + - title: GeoJSON MultiPolygon + required: + - coordinates + - type + type: object + properties: + type: + type: string + enum: + - MultiPolygon + coordinates: + type: array + items: + type: array + items: + minItems: 4 + type: array + items: + minItems: 2 + type: array + items: + type: number + bbox: + minItems: 4 + type: array + items: + type: number + bbox: + minItems: 4 + type: array + items: + type: number + responses: + NotFound: + description: "The requested resource does not exist on the server. For example, a path parameter had an incorrect value." + content: + application/json: + schema: + $ref: "#/components/schemas/exception" + text/html: + schema: + type: string + NotAcceptable: + description: "Content negotiation failed. For example, the `Accept` header submitted in the request did not support any of the media types supported by the server for the requested resource." + content: + application/json: + schema: + $ref: "#/components/schemas/exception" + text/html: + schema: + type: string + ServerError: + description: A server error occurred. + content: + application/json: + schema: + $ref: "#/components/schemas/exception" + text/html: + schema: + type: string + InvalidParameter: + description: A query parameter has an invalid value. + content: + application/json: + schema: + $ref: "#/components/schemas/exception" + text/html: + schema: + type: string + Exception: + description: An error occured. + content: + application/json: + schema: + $ref: "#/components/schemas/exception" + text/html: + schema: + type: string + LandingPage: + description: |- + The landing page provides links to the API definition (link relation `service-desc`, in this case path `/api`), + to the Conformance declaration (path `/conformance`, link relation `conformance`), and to the Collections of geospatial data (path `/collections`, link relation `data`). + content: + application/json: + schema: + $ref: "#/components/schemas/landingPage" + example: + title: Buildings in Bonn + description: Access to data about buildings in the city of Bonn via a Web API that conforms to the OGC API Tiles specification. + links: + - href: http://data.example.org/ + rel: self + type: application/json + title: this document + - href: http://data.example.org/api + rel: service-desc + type: application/vnd.oai.openapi+json;version=3.0 + title: the API definition + - href: http://data.example.org/api.html + rel: service-doc + type: text/html + title: the API documentation + - href: http://data.example.org/conformance + rel: conformance + type: application/json + title: OGC API conformance classes implemented by this service + - href: http://data.example.org/collections + rel: data + type: application/json + title: Information about the collections + text/html: + schema: + type: string + Conformance: + description: The URIs of all conformance classes supported by the server + content: + application/json: + schema: + example: + conformsTo: + - http://www.opengis.net/spec/ogcapi-common-1/1.0/conf/core + - http://www.opengis.net/spec/ogcapi-common-1/1.0/conf/json + - http://www.opengis.net/spec/ogcapi-common-1/1.0/conf/html + - http://www.opengis.net/spec/ogcapi-common-1/1.0/conf/oas30 + - http://www.opengis.net/spec/ogcapi-common-2/1.0/conf/collections + - http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/core + - http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/tileset + - http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/tilesets-list + - http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/geodata-tilesets + - http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/dataset-tilesets + - http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/geodata-selection + - http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/jpeg + - http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/png + - http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/mvt + - http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/geojson + - http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/tiff + - http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/netcdf + allOf: + - $ref: "#/components/schemas/confClasses" + API: + description: The OpenAPI definition of the API. + content: + application/vnd.oai.openapi+json;version=3.0: + schema: + type: object + text/html: + schema: + type: string + Enumeration: + description: An enumerated list of valid string values for API parameters. + content: + application/json: + schema: + $ref: "#/components/schemas/enumeration" + text/html: + schema: + type: string + CollectionsList: + description: |- + The collections of (mostly geospatial) data available from this API. The dataset contains one or more collections. This resource provides information about and access to the collections. The response contains the list of collections. Each collection is accessible via one or more OGC API set of specifications, for which a link to relevant accessible resources, e.g. /collections/{collectionId}/(items, coverage, map, tiles...) is provided, with the corresponding relation type, as well as key information about the collection. This information includes: + * a local identifier for the collection that is unique for the dataset; + * a list of coordinate reference systems (CRS) in which data may be returned by the server. The first CRS is the default coordinate reference system (the default is always WGS 84 with axis order longitude/latitude); + * an optional title and description for the collection; + * an optional extent that can be used to provide an indication of the spatial and temporal extent of the collection - typically derived from the data; + * for collections accessible via the Features or Records API, an optional indicator about the type of the items in the collection (the default value, if the indicator is not provided, is 'feature'). + content: + application/json: + schema: + $ref: "#/components/schemas/collections" + example: + links: + - href: http://data.example.org/collections.json + rel: self + type: application/json + title: this document + - href: http://data.example.org/collections.html + rel: alternate + type: text/html + title: this document as HTML + - href: http://schemas.example.org/1.0/buildings.xsd + rel: describedby + type: application/xml + title: GML application schema for Acme Corporation building data + - href: http://download.example.org/buildings.gpkg + rel: enclosure + type: application/geopackage+sqlite3 + title: Bulk download (GeoPackage) + length: 472546 + collections: + - id: buildings + title: Buildings + description: Buildings in the city of Bonn. + extent: + spatial: + bbox: + - - 7.01 + - 50.63 + - 7.22 + - 50.78 + temporal: + interval: + - - 2010-02-15T12:34:56Z + - null + links: + - href: http://data.example.org/collections/buildings/items + rel: items + type: application/geo+json + title: Buildings + - href: http://data.example.org/collections/buildings/items.html + rel: items + type: text/html + title: Buildings + - href: https://creativecommons.org/publicdomain/zero/1.0/ + rel: license + type: text/html + title: CC0-1.0 + - href: https://creativecommons.org/publicdomain/zero/1.0/rdf + rel: license + type: application/rdf+xml + title: CC0-1.0 + text/html: + schema: + type: string + Collection: + description: |- + Information about a particular collection of (mostly geospatial) data available from this API. The collection is accessible via one or more OGC API set of specifications, for which a link to relevant accessible resources, e.g. /collections/{collectionId}/(items, coverage, map, tiles...) is contained in the response, with the corresponding relation type, as well as key information about the collection. This information includes: + * a local identifier for the collection that is unique for the dataset; + * a list of coordinate reference systems (CRS) in which data may be returned by the server. The first CRS is the default coordinate reference system (the default is always WGS 84 with axis order longitude/latitude); + * an optional title and description for the collection; + * an optional extent that can be used to provide an indication of the spatial and temporal extent of the collection - typically derived from the data; + * for collections accessible via the Features or Records API, an optional indicator about the type of the items in the collection (the default value, if the indicator is not provided, is 'feature'). + content: + application/json: + schema: + $ref: "#/components/schemas/collectionInfo" + example: + id: buildings + title: Buildings + description: Buildings in the city of Bonn. + extent: + spatial: + bbox: + - - 7.01 + - 50.63 + - 7.22 + - 50.78 + temporal: + interval: + - - 2010-02-15T12:34:56Z + - null + links: + - href: http://data.example.org/collections/buildings/items + rel: items + type: application/geo+json + title: Buildings + - href: http://data.example.org/collections/buildings/items.html + rel: items + type: text/html + title: Buildings + - href: https://creativecommons.org/publicdomain/zero/1.0/ + rel: license + type: text/html + title: CC0-1.0 + - href: https://creativecommons.org/publicdomain/zero/1.0/rdf + rel: license + type: application/rdf+xml + title: CC0-1.0 + text/html: + schema: + type: string + TileSetsList: + description: List of available tilesets. + content: + application/json: + schema: + required: + - tilesets + type: object + properties: + links: + type: array + items: + $ref: "#/components/schemas/link" + tilesets: + type: array + items: + $ref: "#/components/schemas/tileSet-item" + text/html: + schema: + type: string + TileSet: + description: Description of the tileset + content: + application/json: + schema: + $ref: "#/components/schemas/tileSet" + text/html: + schema: + type: string + MapTile: + description: A map tile image returned as a response. + content: + image/png: + schema: + type: string + format: binary + image/jpeg: + schema: + type: string + format: binary + image/tiff; application=geotiff: + schema: + type: string + format: binary + CoverageTile: + description: A coverage tile returned as a response. + content: + application/netcdf: + schema: + type: string + format: binary + image/tiff; application=geotiff: + schema: + type: string + format: binary + VectorTile: + description: A vector tile returned as a response. + content: + application/vnd.mapbox-vector-tile: + schema: + type: string + format: binary + application/geo+json: + schema: + allOf: + - format: geojson-feature-collection + - $ref: "#/components/schemas/FeatureCollection" + EmptyTile: + description: No data available for this tile. + TileMatrixSetsList: + description: List of tile matrix sets (tiling schemes). + content: + application/json: + schema: + type: object + properties: + tileMatrixSets: + type: array + items: + $ref: "#/components/schemas/tileMatrixSet-item" + text/html: + schema: + type: string + TileMatrixSet: + description: tile matrix set + content: + application/json: + schema: + $ref: "#/components/schemas/tileMatrixSet" + parameters: + f-metadata: + name: f + in: query + description: "The format of the response. If no value is provided, the accept header is used to determine the format. Accepted values are 'json' or 'html'." + required: false + style: form + explode: false + schema: + type: string + enum: + - json + - html + collectionId-all: + name: collectionId + in: path + description: Local identifier of a collection + required: true + schema: + $ref: "#/components/schemas/all-collections" + collectionId-coverage: + name: collectionId + in: path + description: Local identifier of a coverage collection + required: true + style: simple + explode: false + schema: + $ref: "#/components/schemas/coverage-collections" + collectionId-vectorTiles: + name: collectionId + in: path + description: Local identifier of a vector tile collection + required: true + schema: + $ref: "#/components/schemas/vectorTiles-collections" + collections: + name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/all-collections" + collections-coverage: + name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/coverage-collections" + collections-vectorTiles: + name: collections + in: query + description: "The collections that should be included in the response. The parameter value is a comma-separated list of collection identifiers. If the parameters is missing, some or all collections will be included. The collection will be rendered in the order specified, with the last one showing on top, unless the priority is overridden by styling rules." + required: false + style: form + explode: false + schema: + type: array + items: + $ref: "#/components/schemas/vectorTiles-collections" + datetime: + name: datetime + in: query + description: |- + Either a date-time or an interval, half-bounded or bounded. Date and time expressions + adhere to RFC 3339. Half-bounded intervals are expressed using double-dots. + + Examples: + + * A date-time: "2018-02-12T23:20:50Z" + * A bounded interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" + * Half-bounded intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z" + + Only features that have a temporal property that intersects the value of + `datetime` are selected. + + If a feature has multiple temporal properties, it is the decision of the + server whether only a single temporal property is used to determine + the extent or all relevant temporal properties. + required: false + style: form + explode: false + schema: + type: string + subset: + name: subset + in: query + description: | + Retrieve only part of the data by slicing or trimming along one or more axis + For trimming: {axisAbbrev}({low}:{high}) (preserves dimensionality) + An asterisk (`*`) can be used instead of {low} or {high} to indicate the minimum/maximum value. + For slicing: {axisAbbrev}({value}) (reduces dimensionality) + required: false + style: form + explode: false + schema: + type: array + items: + type: string + crs: + name: crs + in: query + description: reproject the output to the given crs + required: false + style: form + explode: true + schema: + type: string + subset-crs: + name: subset-crs + in: query + description: crs for the specified subset + required: false + style: form + explode: true + schema: + type: string + tileMatrix: + name: tileMatrix + in: path + description: |- + Identifier selecting one of the scales defined in the TileMatrixSet and representing the scaleDenominator the tile. For example, + Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15. + required: true + schema: + type: string + example: "5" + tileRow: + name: tileRow + in: path + description: "Row index of the tile on the selected TileMatrix. It cannot exceed the MatrixWidth-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 10 + tileCol: + name: tileCol + in: path + description: "Column index of the tile on the selected TileMatrix. It cannot exceed the MatrixHeight-1 for the selected TileMatrix. For example, Ireland is fully within the Tile at WebMercatorQuad tileMatrix=5, tileRow=10 and tileCol=15." + required: true + schema: + minimum: 0 + type: integer + example: 15 + tileMatrixSetId: + name: tileMatrixSetId + in: path + description: Identifier for a supported TileMatrixSet + required: true + schema: + $ref: "#/components/schemas/tileMatrixSets" + f-mapTile: + name: f + in: query + description: "The format of the map tile response (e.g. png). Accepted values are 'png', 'jpg' or 'tiff' (GeoTIFF)." + required: false + style: form + explode: false + schema: + type: string + enum: + - png + - jpg + - tiff + f-vectorTile: + name: f + in: query + description: The format of the vector tile response (e.g. json). Accepted values are 'mvt' (Mapbox Vector Tiles) or 'json' (GeoJSON). + required: false + style: form + explode: false + schema: + type: string + enum: + - mvt + - json + f-coverageTile: + name: f + in: query + description: "The format of the coverage tile response (e.g. tiff). Accepted values are 'tiff' (GeoTIFF), 'netcdf', or 'png'." + required: false + style: form + explode: false + schema: + type: string + enum: + - tiff + - netcdf + - png + bgcolor: + name: bgcolor + in: query + description: "Web color name or hexadecimal 0x[AA]RRGGBB color value for the background color (default to 0x9C9C9C gray). If alpha is not specified, full opacity is assumed." + required: false + style: form + explode: false + schema: + type: string + default: 0xFFFFFF + transparent: + name: transparent + in: query + description: Background transparency of map (default=true). + required: false + style: form + explode: false + schema: + type: boolean + default: true + styleId: + name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + $ref: "#/components/schemas/styles" + styleId-collection: + name: styleId + in: path + description: An identifier representing a specific style. + required: true + schema: + type: string diff --git a/docs/openapi.yaml b/docs/openapi.yaml index 86e0ab9..1730c81 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -4,14 +4,9 @@ info: description: Le serveur implémente les standards ouverts de l’Open Geospatial Consortium (OGC) WMS 1.3.0 et WMTS 1.0.0, ainsi que le TMS (Tile Map Service). version: "__version__" servers: -- url: https://tuiles.ign.fr/rok4 +- url: http://localhost/data tags: -- name: OGC API Common - description: Découverte des services du serveur - externalDocs: - description: Spécifications OGC - url: https://ogcapi.ogc.org/common/ - name: Santé du serveur description: Informations de santé sur les serveur - name: Web Map Tile Service @@ -29,32 +24,16 @@ tags: externalDocs: description: Spécifications OSGeo url: https://wiki.osgeo.org/wiki/Tile_Map_Service_Specification -- name: OGC API Tiles - description: Diffusion de tuiles raster et vecteur selon le standard l'API OGC - Tiles +- name: OGC API + description: Diffusion de données vecteur et raster selon les standards Tiles et Maps de l'API OGC externalDocs: description: Spécifications OGC - url: https://ogcapi.ogc.org/tiles/ + url: https://ogcapi.ogc.org/ - name: Administration description: API d'ajout et de suppression de couches disponibles paths: - ######################################### COMMON - - /common: - get: - tags: - - OGC API Common - summary: Retourne la liste des services disponibles - operationId: common_get_services - responses: - 200: - description: Services assurés par le serveur - content: - application/json: - schema: - $ref: '#/components/schemas/common_get_services' - ######################################### SANTÉ DU SERVEUR /healthcheck: @@ -845,15 +824,14 @@ paths: type: string format: binary - ######################################### OGC API Tiles - + ######################################### OGC API - /tiles: + /ogcapi: get: tags: - - OGC API Tiles - summary: Retourne la page d'accueil du service OGC API Tiles - operationId: tiles_get_landing_page + - OGC API + summary: Retourne la page d'accueil du service OGC API + operationId: ogcapi_get_landing_page parameters: - name: f required: false @@ -864,18 +842,18 @@ paths: enum: ['json'] responses: 200: - description: Services assurés par le service OGC API Tiles + description: Services assurés par les services OGC API content: application/json: schema: - $ref: '#/components/schemas/tiles_get_landing_page' + $ref: '#/components/schemas/ogcapi_get_landing_page' - /tiles/conformance: + /ogcapi/conformance: get: tags: - - OGC API Tiles - summary: Retourne la liste des classes de conformité du service OGC API Tiles - operationId: tiles_get_conformance + - OGC API + summary: Retourne la liste des classes de conformité du service OGC API + operationId: ogcapi_get_conformance parameters: - name: f required: false @@ -890,15 +868,17 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ogc_get_conformance' + $ref: '#/components/schemas/ogcapi_get_conformance' - /tiles/collections: + + /ogcapi/api/all-collections: get: tags: - - OGC API Tiles - summary: Récupère la liste des couches disponibles - operationId: ogc_get_collections + - OGC API + summary: Récupère la liste des valeurs de collection possibles + operationId: ogc_get_api_collections parameters: + - name: f required: false in: query @@ -907,23 +887,176 @@ paths: type: string enum: ['json'] - # - name: bbox - # required: false - # in: query - # description: Seules les collections dont la géométrie intersecte la "bounding box" sont sélectionnées. - # schema: - # type: array - # minItems: 4 - # maxItems: 4 - # items: - # type: number - # format: double - # example: - # - 450000 - # - 560000 - # - 455000 - # - 565000 - # explode: false + responses: + 200: + description: Liste des valeurs de collection possibles + content: + application/json: + schema: + $ref: '#/components/schemas/ogcapi_api_params' + + /ogcapi/api/vectorTiles-collections: + get: + tags: + - OGC API + summary: Récupère la liste des valeurs de collection tuile vectorielle possibles + operationId: ogc_get_api_vectortiles_collections + parameters: + + - name: f + required: false + in: query + description: format de sortie demandé + schema: + type: string + enum: ['json'] + + responses: + 200: + description: Liste des valeurs de collection tuile vectorielle possibles + content: + application/json: + schema: + $ref: '#/components/schemas/ogcapi_api_params' + + + /ogcapi/api/styles: + get: + tags: + - OGC API + summary: Récupère la liste des valeurs de style possibles + operationId: ogc_get_api_styles + parameters: + + - name: f + required: false + in: query + description: format de sortie demandé + schema: + type: string + enum: ['json'] + + responses: + 200: + description: Liste des valeurs de style possibles + content: + application/json: + schema: + $ref: '#/components/schemas/ogcapi_api_params' + + + /ogcapi/api/tileMatrixSets: + get: + tags: + - OGC API + summary: Récupère la liste des valeurs de tile matrix set possibles + operationId: ogc_get_api_tilematrixsets + parameters: + + - name: f + required: false + in: query + description: format de sortie demandé + schema: + type: string + enum: ['json'] + + responses: + 200: + description: Liste des valeurs de tile matrix set possibles + content: + application/json: + schema: + $ref: '#/components/schemas/ogcapi_api_params' + + + /ogcapi/tileMatrixSets: + get: + tags: + - OGC API + summary: Récupère la liste des tile matrix sets disponibles + operationId: ogc_get_tilematrixsets + parameters: + + - name: f + required: false + in: query + description: format de sortie demandé + schema: + type: string + enum: ['json'] + + responses: + 200: + description: Liste des tile matrix sets disponibles + content: + application/json: + schema: + $ref: '#/components/schemas/ogcapi_tilematrixsets' + + /ogcapi/tileMatrixSets/{tms}: + get: + tags: + - OGC API + summary: Récupère les informations sur un tile matrix set + operationId: ogc_get_tilematrixset + parameters: + + - name: tms + required: true + in: path + description: tile matrix set demandé + schema: + type: string + + - name: f + required: false + in: query + description: format de sortie demandé + schema: + type: string + enum: ['json'] + + responses: + 200: + description: Définition du TMS + content: + application/json: + schema: + $ref: '#/components/schemas/ogcapi_tilematrixset' + + /ogcapi/collections: + get: + tags: + - OGC API + summary: Récupère la liste des collections disponibles + operationId: ogcapi_get_collections + parameters: + - name: f + required: false + in: query + description: format de sortie demandé + schema: + type: string + enum: ['json'] + + - name: bbox + required: false + in: query + description: Seules les collections dont la géométrie intersecte la "bounding box" sont sélectionnées. Le format est east,south,west,north (en CRS84) + schema: + type: array + minItems: 4 + maxItems: 4 + items: + type: number + format: double + example: + - -5 + - 40 + - 5 + - 50 + explode: false # - name: limit # required: false @@ -937,33 +1070,33 @@ paths: responses: 200: - description: Liste des couches disponibles + description: Liste des collections disponibles content: application/json: schema: type: array items: - $ref: '#/components/schemas/tiles_collections' + $ref: '#/components/schemas/ogcapi_collections' 400: description: Format demandé invalide content: application/json: schema: - $ref: '#/components/schemas/tiles_error' + $ref: '#/components/schemas/ogcapi_error' - /tiles/collections/{layer}: + /ogcapi/collections/{collection}: get: tags: - - OGC API Tiles - summary: Récupère une couche disponible - operationId: ogc_get_collection + - OGC API + summary: Récupère une collection disponible + operationId: ogcapi_get_collection parameters: - - name: layer + - name: collection required: true in: path - description: couche demandée + description: collection demandée schema: type: string @@ -977,37 +1110,37 @@ paths: responses: 200: - description: Couche demandée + description: Collection demandée content: application/json: schema: - $ref: '#/components/schemas/tiles_layer' + $ref: '#/components/schemas/ogcapi_collection' 400: - description: Format demandé invalide + description: Collection demandé invalide content: application/json: schema: - $ref: '#/components/schemas/tiles_error' + $ref: '#/components/schemas/ogcapi_error' 404: - description: Couche inconnue + description: Collection inconnue content: application/json: schema: - $ref: '#/components/schemas/tiles_error' + $ref: '#/components/schemas/ogcapi_error' - /tiles/collections/{layer}/tiles: + /ogcapi/collections/{collection}/tiles: get: tags: - - OGC API Tiles - summary: Récupère les TMS disponibles pour une couche vecteur - operationId: ogc_get_vector_tilesets + - OGC API + summary: Récupère les TMS disponibles pour une collection tuilée vecteur + operationId: ogcapi_tiles_get_vector_tilesets parameters: - - name: layer + - name: collection required: true in: path - description: couche demandée + description: Collection demandée schema: type: string @@ -1021,37 +1154,37 @@ paths: responses: 200: - description: Couche demandée + description: TMS de la collection demandée content: application/json: schema: - $ref: '#/components/schemas/tiles_tilesets' + $ref: '#/components/schemas/ogcapi_tiles_tilesets' 400: - description: Format demandé invalide ou la couche demandée correspond à de la donnée raster + description: Format demandé invalide ou la collection demandée correspond à de la donnée raster content: application/json: schema: - $ref: '#/components/schemas/tiles_error' + $ref: '#/components/schemas/ogcapi_error' 404: - description: Couche inconnue + description: Collection inconnue content: application/json: schema: - $ref: '#/components/schemas/tiles_error' + $ref: '#/components/schemas/ogcapi_error' - /tiles/collections/{layer}/tiles/{tms}: + /ogcapi/collections/{collection}/tiles/{tms}: get: tags: - - OGC API Tiles - summary: Récupère les niveaux disponibles pour une couche vecteur - operationId: ogc_get_vector_tileset + - OGC API + summary: Récupère les niveaux disponibles pour une collection vecteur + operationId: ogcapi_tiles_get_vector_tileset parameters: - - name: layer + - name: collection required: true in: path - description: couche demandée + description: collection demandée schema: type: string @@ -1072,88 +1205,115 @@ paths: responses: 200: - description: Couche demandée + description: Niveaux de la collection demandée content: application/json: schema: - $ref: '#/components/schemas/tiles_tileset' + $ref: '#/components/schemas/ogcapi_tiles_tileset' 400: - description: Format demandé invalide ou la couche demandée correspond à de la donnée raster + description: Format demandé invalide ou la collection demandée correspond à de la donnée raster content: application/json: schema: - $ref: '#/components/schemas/tiles_error' + $ref: '#/components/schemas/ogcapi_error' 404: - description: Couche ou TMS inconnu + description: Collection ou TMS inconnu content: application/json: schema: - $ref: '#/components/schemas/tiles_error' + $ref: '#/components/schemas/ogcapi_error' - - /tiles/collections/{layer}/styles: + /ogcapi/collections/{collection}/tiles/{tms}/{level}/{row}/{col}: get: tags: - - OGC API Tiles - summary: Récupère les styles disponibles pour une couche raster - operationId: ogc_get_raster_styles + - OGC API + summary: Télécharge une tuile vecteur + operationId: ogc_get_vector_tile parameters: - - name: layer + - name: collection required: true in: path - description: couche demandée + description: collection demandée schema: type: string - + + - name: tms + required: true + in: path + description: TMS demandé + schema: + type: string + + - name: level + required: true + in: path + description: niveau de la tuile demandée + schema: + type: integer + + - name: row + required: true + in: path + description: ligne de la tuile demandée + schema: + type: integer + + - name: col + required: true + in: path + description: colonne de la tuile demandée + schema: + type: integer + - name: f required: false in: query - description: format de sortie demandé + description: format demandé schema: type: string - enum: ['json'] + enum: ["mvt"] + - name: filename + required: false + in: query + description: nom du fichier à enregistrer (mis dans le content-disposition de la réponse, avec le mode attachment) + schema: + type: string + responses: 200: - description: Couche demandée + description: Tuile vecteur demandée content: - application/json: + application/octet-stream: schema: - $ref: '#/components/schemas/tiles_styles' + type: string + format: binary 400: - description: Format demandé invalide ou la couche demandée correspond à de la donnée vecteur + description: La collection demandée correspond à de la donnée raster content: application/json: schema: - $ref: '#/components/schemas/tiles_error' + $ref: '#/components/schemas/ogcapi_error' 404: - description: Couche inconnue + description: Collection inconnue content: application/json: schema: - $ref: '#/components/schemas/tiles_error' + $ref: '#/components/schemas/ogcapi_error' - - /tiles/collections/{layer}/styles/{style}/map/tiles: + /ogcapi/collections/{collection}/map/tiles: get: tags: - - OGC API Tiles - summary: Récupère les TMS disponibles pour une couche raster - operationId: ogc_get_raster_tilesets + - OGC API + summary: Récupère les TMS disponibles pour une collection raster + operationId: ogc_tiles_get_raster_tilesets parameters: - - name: layer + - name: collection required: true in: path - description: couche demandée - schema: - type: string - - - name: style - required: true - in: path - description: style demandé + description: collection demandée schema: type: string @@ -1167,44 +1327,37 @@ paths: responses: 200: - description: Couche demandée + description: TMS de la collection demandée content: application/json: schema: - $ref: '#/components/schemas/tiles_tilesets' + $ref: '#/components/schemas/ogcapi_tiles_tilesets' 400: description: Format demandé invalide ou la couche demandée correspond à de la donnée vecteur content: application/json: schema: - $ref: '#/components/schemas/tiles_error' + $ref: '#/components/schemas/ogcapi_error' 404: description: Couche ou style inconnu content: application/json: schema: - $ref: '#/components/schemas/tiles_error' + $ref: '#/components/schemas/ogcapi_error' - /tiles/collections/{layer}/styles/{style}/map/tiles/{tms}: + /ogcapi/collections/{collection}/map/tiles/{tms}: get: tags: - - OGC API Tiles + - OGC API summary: Récupère les niveaux disponibles pour une couche raster - operationId: ogc_get_raster_tileset + operationId: ogc_tiles_get_raster_tileset parameters: - - name: layer - required: true - in: path - description: couche demandée - schema: - type: string - - - name: style + - name: collection required: true in: path - description: style demandé + description: collection demandée schema: type: string @@ -1225,36 +1378,36 @@ paths: responses: 200: - description: Couche demandée + description: Niveaux de la collection demandée content: application/json: schema: - $ref: '#/components/schemas/tiles_tileset' + $ref: '#/components/schemas/ogcapi_tiles_tileset' 400: - description: Format demandé invalide ou la couche demandée correspond à de la donnée vecteur + description: Format demandé invalide ou la collection demandée correspond à de la donnée vecteur content: application/json: schema: - $ref: '#/components/schemas/tiles_error' + $ref: '#/components/schemas/ogcapi_error' 404: - description: Couche, style ou TMS inconnu + description: Collection, style ou TMS inconnu content: application/json: schema: - $ref: '#/components/schemas/tiles_error' + $ref: '#/components/schemas/ogcapi_error' - /tiles/collections/{layer}/styles/{style}/map/tiles/{tms}/{level}/{row}/{col}: + /ogcapi/collections/{collection}/styles/{style}/map/tiles/{tms}/{level}/{row}/{col}: get: tags: - - OGC API Tiles + - OGC API summary: Télécharge une tuile raster - operationId: ogc_get_raster_tile + operationId: ogc_tiles_get_raster_tile parameters: - - name: layer + - name: collection required: true in: path - description: couche demandée + description: collection demandée schema: type: string @@ -1299,7 +1452,7 @@ paths: description: format demandé schema: type: string - enum: ["png", "jpg", "tiff"] + enum: ["png", "jpg", "tiff", "bil"] - name: filename required: false @@ -1317,69 +1470,106 @@ paths: type: string format: binary 400: - description: La couche demandée correspond à de la donnée vecteur + description: La collection demandée correspond à de la donnée vecteur content: application/json: schema: - $ref: '#/components/schemas/tiles_error' + $ref: '#/components/schemas/ogcapi_error' 404: - description: Couche inconnue + description: Collection inconnue content: application/json: schema: - $ref: '#/components/schemas/tiles_error' - + $ref: '#/components/schemas/ogcapi_error' - /tiles/collections/{layer}/tiles/{tms}/{level}/{row}/{col}: + /ogcapi/collections/{collection}/styles/{style}/map: get: tags: - - OGC API Tiles - summary: Télécharge une tuile vecteur - operationId: ogc_get_vector_tile + - OGC API + summary: Télécharge une image + operationId: ogc_maps_get_map parameters: - - name: layer + - name: collection required: true in: path - description: couche demandée + description: collection demandée schema: type: string - - name: tms + - name: style required: true in: path - description: TMS demandé + description: style à appliquer schema: type: string - - name: level - required: true - in: path - description: niveau de la tuile demandée + - name: bbox + required: false + in: query + description: Rectangle englobant de l'image demandée en CRS84 (longitude/latitude) si bbox-crs n'est pas renseigné. On prend la bbox globale des données si non fournie. schema: - type: integer + type: array + minItems: 4 + maxItems: 6 + items: + type: number + format: double + example: + - -5 + - 40 + - 5 + - 50 + explode: false - - name: row - required: true - in: path - description: ligne de la tuile demandée + - name: bbox-crs + required: false + in: query + description: Système de coordonnée du rectangle englobant dans le paramètre bbox, CRS84 par défaut si la bbox est fournie, celui de la donnée sinon + schema: + type: string + example: + EPSG:4326 + + - name: crs + required: false + in: query + description: Système de coordonnée de l'image retournée. Celui natif des données si non fourni. + schema: + type: string + example: + EPSG:3857 + + - name: width + required: false + in: query + description: largeur de l'image demandée. Si non fournie, on respecte le ratio de la bbox. Si aucune dimension n'est fournie, on met la plus grande à une valeur par défaut et l'autre en respectant le ratio de la bbox. schema: type: integer - - name: col - required: true - in: path - description: colonne de la tuile demandée + - name: height + required: false + in: query + description: hauteur de l'image demandée. Si non fournie, on respecte le ratio de la bbox. Si aucune dimension n'est fournie, on met la plus grande à une valeur par défaut et l'autre en respectant le ratio de la bbox. schema: type: integer + - name: mm-per-pixel + required: false + in: query + description: résolution de l'image demandée + schema: + type: number + default: + 0.28 + - name: f required: false in: query - description: format demandé + description: format demandé, celui natif des données si non fourni schema: type: string - enum: ["mvt"] + enum: ["png", "jpg", "tiff", "bil", "asc"] - name: filename required: false @@ -1390,79 +1580,136 @@ paths: responses: 200: - description: Tuile vecteur demandée + description: Image demandée content: application/octet-stream: schema: type: string format: binary 400: - description: La couche demandée correspond à de la donnée raster + description: La collection demandée correspond à de la donnée vecteur content: application/json: schema: - $ref: '#/components/schemas/tiles_error' + $ref: '#/components/schemas/ogcapi_error' 404: - description: Couche inconnue + description: Collection inconnue content: application/json: schema: - $ref: '#/components/schemas/tiles_error' + $ref: '#/components/schemas/ogcapi_error' - /tiles/tileMatrixSets: + /ogcapi/collections/{collection}/map: get: tags: - - OGC API Tiles - summary: Récupère la liste des tile matrix sets disponibles - operationId: ogc_get_tilematrixsets + - OGC API + summary: Télécharge une image avec le style par défaut + operationId: ogc_maps_get_map_default_style parameters: - - - name: f + + - name: collection + required: true + in: path + description: collection demandée + schema: + type: string + + - name: bbox required: false in: query - description: format de sortie demandé + description: Rectangle englobant de l'image demandée en CRS84 (longitude/latitude) si bbox-crs n'est pas renseigné. On prend la bbox globale des données si non fournie. schema: - type: string - enum: ['json'] + type: array + minItems: 4 + maxItems: 6 + items: + type: number + format: double + example: + - -5 + - 40 + - 5 + - 50 + explode: false - responses: - 200: - description: Liste des tile matrix sets disponibles - content: - application/json: - schema: - $ref: '#/components/schemas/tiles_tilematrixsets' - - /tiles/tileMatrixSets/{tms}: - get: - tags: - - OGC API Tiles - summary: Récupère les informations sur un tile matrix set - operationId: ogc_get_tilematrixset - parameters: + - name: bbox-crs + required: false + in: query + description: Système de coordonnée du rectangle englobant dans le paramètre bbox, CRS84 par défaut si la bbox est fournie, celui de la donnée sinon + schema: + type: string + example: + EPSG:4326 - - name: tms - required: true - in: path - description: tile matrix set demandé + - name: crs + required: false + in: query + description: Système de coordonnée de l'image retournée. Celui natif des données si non fourni. schema: type: string - + example: + EPSG:3857 + + - name: width + required: false + in: query + description: largeur de l'image demandée. Si non fournie, on respecte le ratio de la bbox. Si aucune dimension n'est fournie, on met la plus grande à une valeur par défaut et l'autre en respectant le ratio de la bbox. + schema: + type: integer + + - name: height + required: false + in: query + description: hauteur de l'image demandée. Si non fournie, on respecte le ratio de la bbox. Si aucune dimension n'est fournie, on met la plus grande à une valeur par défaut et l'autre en respectant le ratio de la bbox. + schema: + type: integer + + - name: mm-per-pixel + required: false + in: query + description: résolution de l'image demandée + schema: + type: number + default: + 0.28 + - name: f required: false in: query - description: format de sortie demandé + description: format demandé, celui natif des données si non fourni schema: type: string - enum: ['json'] - + enum: ["png", "jpg", "tiff", "bil", "asc"] + + - name: filename + required: false + in: query + description: nom du fichier à enregistrer (mis dans le content-disposition de la réponse, avec le mode attachment) + schema: + type: string + responses: 200: - description: Définition du TMS + description: Image demandée + content: + application/octet-stream: + schema: + type: string + format: binary + 400: + description: La collection demandée correspond à de la donnée vecteur + content: + application/json: + schema: + $ref: '#/components/schemas/ogcapi_error' + 404: + description: Collection inconnue content: application/json: schema: - $ref: '#/components/schemas/tiles_tilematrixset' + $ref: '#/components/schemas/ogcapi_error' + + ######################################### ADMIN @@ -1473,10 +1720,17 @@ paths: summary: Active les services description: On active la réponse aux appels sur les routes globales et de consultation operationId: admin_turn_on - + security: + - ApiKeyAuth: [] responses: 204: description: Activation des services réussie + 403: + description: Action non autorisée + content: + application/json: + schema: + $ref: '#/components/schemas/admin_error' /admin/off: put: @@ -1487,10 +1741,17 @@ paths: On désactive la réponse aux appels sur les routes globales et de consultation (réponse d'un 503 systématique). On répond toujours aux API admin et de santé. operationId: admin_turn_off - + security: + - ApiKeyAuth: [] responses: 204: description: Désactivation des services réussie + 403: + description: Action non autorisée + content: + application/json: + schema: + $ref: '#/components/schemas/admin_error' /admin/layers/{layername}: post: @@ -1498,6 +1759,8 @@ paths: - Administration summary: Création d'une nouvelle couche operationId: admin_create_layer + security: + - ApiKeyAuth: [] parameters: - name: layername required: true @@ -1522,6 +1785,12 @@ paths: application/json: schema: $ref: '#/components/schemas/admin_error' + 403: + description: Action non autorisée + content: + application/json: + schema: + $ref: '#/components/schemas/admin_error' 409: description: Couche déjà existante content: @@ -1534,6 +1803,8 @@ paths: summary: Modification d'une couche description: L'identifiant de la couche doit rester le même operationId: admin_update_layer + security: + - ApiKeyAuth: [] parameters: - name: layername required: true @@ -1557,6 +1828,12 @@ paths: application/json: schema: $ref: '#/components/schemas/admin_error' + 403: + description: Action non autorisée + content: + application/json: + schema: + $ref: '#/components/schemas/admin_error' 404: description: Couche inexistante content: @@ -1569,6 +1846,8 @@ paths: - Administration summary: Suppression d'une couche operationId: admin_delete_layer + security: + - ApiKeyAuth: [] parameters: - name: layername required: true @@ -1580,6 +1859,12 @@ paths: responses: 204: description: Couche supprimée + 403: + description: Action non autorisée + content: + application/json: + schema: + $ref: '#/components/schemas/admin_error' 404: description: Couche inexistante content: @@ -1588,6 +1873,12 @@ paths: $ref: '#/components/schemas/admin_error' components: + securitySchemes: + ApiKeyAuth: + type: apiKey + in: header + name: X-Rok4-Secret + schemas: common_error: @@ -1674,7 +1965,7 @@ components: type: object additionalProperties: false - common_metadata: + ogcapi_metadata: type: object properties: href: @@ -1687,19 +1978,7 @@ components: title: type: string - common_get_services: - type: object - properties: - title: - type: string - description: - type: string - links: - type: array - items: - $ref: '#/components/schemas/common_metadata' - - tiles_bbox: + ogcapi_bbox: type: object properties: spatial: @@ -1718,7 +1997,7 @@ components: maxItems: 4 example: [-5, 40, 5, 50] - tiles_link: + ogcapi_link: type: object properties: href: @@ -1732,7 +2011,7 @@ components: type: string - tiles_get_landing_page: + ogcapi_get_landing_page: type: object properties: title: @@ -1742,9 +2021,9 @@ components: links: type: array items: - $ref: '#/components/schemas/common_metadata' + $ref: '#/components/schemas/ogcapi_metadata' - ogc_get_conformance: + ogcapi_get_conformance: type: object properties: conformsTo: @@ -1753,17 +2032,17 @@ components: type: string format: uri - tiles_collections: + ogcapi_collections: type: object properties: links: type: array items: - $ref: '#/components/schemas/tiles_link' + $ref: '#/components/schemas/ogcapi_link' collections: type: array items: - $ref: '#/components/schemas/tiles_layer' + $ref: '#/components/schemas/ogcapi_collection' numberMatched: type: integer description: Nombre total de couches correspondantes à la requête @@ -1773,7 +2052,7 @@ components: description: Nombre de couches correspondantes à la requête retournées example: 1 - tiles_layer: + ogcapi_collection: type: object properties: id: @@ -1783,11 +2062,11 @@ components: description: type: string extent: - $ref: '#/components/schemas/tiles_bbox' + $ref: '#/components/schemas/ogcapi_bbox' links: type: array items: - $ref: '#/components/schemas/tiles_link' + $ref: '#/components/schemas/ogcapi_link' crs: type: array items: @@ -1804,7 +2083,7 @@ components: maxCellSize: type: number - tiles_styles: + ogcapi_styles: type: object properties: id: @@ -1814,7 +2093,7 @@ components: links: type: array items: - $ref: '#/components/schemas/tiles_link' + $ref: '#/components/schemas/ogcapi_link' styles: type: array items: @@ -1827,15 +2106,15 @@ components: links: type: array items: - $ref: '#/components/schemas/tiles_link' + $ref: '#/components/schemas/ogcapi_link' - tiles_tilesets: + ogcapi_tiles_tilesets: type: object properties: links: type: array items: - $ref: '#/components/schemas/tiles_link' + $ref: '#/components/schemas/ogcapi_link' tilesets: type: array items: @@ -1853,9 +2132,9 @@ components: links: type: array items: - $ref: '#/components/schemas/tiles_link' + $ref: '#/components/schemas/ogcapi_link' - tiles_tileset: + ogcapi_tiles_tileset: type: object properties: title: @@ -1872,7 +2151,7 @@ components: links: type: array items: - $ref: '#/components/schemas/tiles_link' + $ref: '#/components/schemas/ogcapi_link' tileMatrixSetLimits: type: array items: @@ -1889,7 +2168,7 @@ components: maxTileCol: type: integer - tiles_tilematrixsets: + ogcapi_tilematrixsets: type: object properties: tilematrixsets: @@ -1904,9 +2183,21 @@ components: links: type: array items: - $ref: '#/components/schemas/tiles_link' + $ref: '#/components/schemas/ogcapi_link' + + ogcapi_api_params: + type: object + properties: + type: + type: string + enum: + - "enum" + enum: + type: array + items: + type: string - tiles_tilematrixset: + ogcapi_tilematrixset: type: object properties: id: @@ -1949,7 +2240,7 @@ components: type: integer - tiles_error: + ogcapi_error: type: object additionalProperties: false properties: @@ -2224,7 +2515,7 @@ components: pyramid: type: boolean - tiles: + ogcapi: type: object properties: pyramid: diff --git a/src/configurations/Attribution.h b/src/configurations/Attribution.h index f3bb389..279160c 100644 --- a/src/configurations/Attribution.h +++ b/src/configurations/Attribution.h @@ -47,7 +47,7 @@ #include -#include "Utils.h" +#include "core/Utils.h" /** * \author Institut national de l'information géographique et forestière @@ -169,6 +169,14 @@ class Attribution : public ResourceLocator { } } + /** + * \~french \brief Retourne le titre + * \~english \brief Get the title + */ + std::string get_title() { + return title; + } + /** * \~french * \brief Destructeur par défaut diff --git a/src/configurations/Layer.cpp b/src/configurations/Layer.cpp index 62d2240..6195219 100644 --- a/src/configurations/Layer.cpp +++ b/src/configurations/Layer.cpp @@ -55,7 +55,7 @@ #include #include "configurations/Layer.h" -#include "Inspire.h" +#include "core/Inspire.h" bool is_style_handled(Style* style) { if (style->get_identifier() == "") return false; @@ -64,7 +64,7 @@ bool is_style_handled(Style* style) { return true; } -bool Layer::parse(json11::Json& doc, ServicesConfiguration* services) { +bool Layer::parse(json11::Json& doc) { /********************** Default values */ @@ -74,7 +74,7 @@ bool Layer::parse(json11::Json& doc, ServicesConfiguration* services) { wms = true; wmts = true; tms = true; - tiles = true; + ogcapi = true; gfi_enabled = false; gfi_type = ""; @@ -265,11 +265,13 @@ bool Layer::parse(json11::Json& doc, ServicesConfiguration* services) { if (doc["tms"].is_object() && doc["tms"]["enabled"].is_bool()) { tms = doc["tms"]["enabled"].bool_value(); } - if (doc["tiles"].is_object() && doc["tiles"]["enabled"].is_bool()) { - tiles = doc["tiles"]["enabled"].bool_value(); + if (doc["ogcapi"].is_object() && doc["ogcapi"]["enabled"].is_bool()) { + ogcapi = doc["ogcapi"]["enabled"].bool_value(); } - if (Rok4Format::is_raster(pyramid->get_format())) { + raster = Rok4Format::is_raster(pyramid->get_format()); + + if (raster) { /******************* CAS RASTER *********************/ // Configuration du GET FEATURE INFO @@ -347,7 +349,7 @@ bool Layer::parse(json11::Json& doc, ServicesConfiguration* services) { } if ( available_styles.size() == 0 ) { - Style* sty = StyleBook::get_style(services->get_default_style_id()); + Style* sty = StyleBook::get_style(services->default_style); if ( sty == NULL ) { error_message = "No valid style (even the default one), the layer is not valid" ; return false; @@ -361,7 +363,7 @@ bool Layer::parse(json11::Json& doc, ServicesConfiguration* services) { // Configuration des reprojections possibles - // TMS additionnels (pour le WMTS et l'API Tiles) + // TMS additionnels (pour le WMTS et l'OGC API Tiles) if (doc["extra_tilematrixsets"].is_array()) { for (json11::Json t : doc["extra_tilematrixsets"].array_items()) { if (! t.is_string()) { @@ -401,7 +403,7 @@ bool Layer::parse(json11::Json& doc, ServicesConfiguration* services) { continue; } - if (services->get_wms_service()->is_available_crs(str_crs)) { + if (services->is_map_available_crs(str_crs)) { // Cette projection est déjà disponible globalement au niveau du service continue; } @@ -432,8 +434,8 @@ bool Layer::parse(json11::Json& doc, ServicesConfiguration* services) { calculate_tilematrix_limits(); - if (! Rok4Format::is_raster(pyramid->get_format())) { - // Une pyramide vecteur n'est diffusée qu'en TMS et API TILES et le GFI n'est pas possible + if (! raster) { + // Une pyramide vecteur n'est diffusée qu'en TMS et OGC API TILES et le GFI n'est pas possible wms = false; wms_inspire = false; wmts = false; @@ -546,7 +548,9 @@ void Layer::calculate_tilematrix_limits() { } } -Layer::Layer(std::string path, ServicesConfiguration* services) : Configuration(path), pyramid(NULL), attribution(NULL) { +Layer::Layer(std::string path, ServicesConfiguration* s) : Configuration(path), pyramid(NULL), attribution(NULL) { + + services = s; /********************** Id */ @@ -591,7 +595,7 @@ Layer::Layer(std::string path, ServicesConfiguration* services) : Configuration( /********************** Parse */ - if (! parse(doc, services)) { + if (! parse(doc)) { return; } @@ -599,7 +603,9 @@ Layer::Layer(std::string path, ServicesConfiguration* services) : Configuration( } -Layer::Layer(std::string layer_name, std::string content, ServicesConfiguration* services ) : Configuration(), id(layer_name), pyramid(NULL), attribution(NULL) { +Layer::Layer(std::string layer_name, std::string content, ServicesConfiguration* s ) : Configuration(), id(layer_name), pyramid(NULL), attribution(NULL) { + + services = s; /********************** Id */ @@ -619,7 +625,7 @@ Layer::Layer(std::string layer_name, std::string content, ServicesConfiguration* /********************** Parse */ - if (! parse(doc, services)) { + if (! parse(doc)) { return; } @@ -646,7 +652,8 @@ bool Layer::is_wms_inspire() { return wms_inspire; } bool Layer::is_tms_enabled() { return tms; } bool Layer::is_wmts_enabled() { return wmts; } bool Layer::is_wmts_inspire() { return wmts_inspire; } -bool Layer::is_tiles_enabled() { return tiles; } +bool Layer::is_ogcapi_enabled() { return ogcapi; } +bool Layer::is_raster() { return raster; } std::vector* Layer::get_keywords() { return &keywords; } Pyramid* Layer::get_pyramid() { return pyramid; } Style* Layer::get_default_style() { @@ -771,8 +778,8 @@ void Layer::add_node_wmts(ptree& parent, WmtsService* service, bool only_inspire node.add("Format", Rok4Format::to_mime_type ( pyramid->get_format() )); if (gfi_enabled){ - for ( unsigned int j = 0; j < service->get_available_infoformats()->size(); j++ ) { - node.add("InfoFormat", service->get_available_infoformats()->at ( j )); + for ( unsigned int j = 0; j < services->get_available_infoformats()->size(); j++ ) { + node.add("InfoFormat", services->get_available_infoformats()->at ( j )); } } @@ -792,7 +799,7 @@ void Layer::add_node_wmts(ptree& parent, WmtsService* service, bool only_inspire used_tms_list->emplace ( tmsi->request_id , tmsi ); // Si la reprojection WMTS n'est pas activée, nous n'exposons que le premier TMS, celui natif - if (! service->reprojection_enabled()) { + if (! services->tile_reprojection) { break; } } @@ -833,7 +840,7 @@ void Layer::add_node_wms(ptree& parent, WmsService* service, bool only_inspire) node.add("CRS", c->get_request_code()); // Si la reprojection WMS n'est pas activée, nous n'exposons que le premier CRS, celui natif - if (! service->reprojection_enabled()) { + if (! services->map_reprojection) { break; } } @@ -854,13 +861,13 @@ void Layer::add_node_wms(ptree& parent, WmsService* service, bool only_inspire) bbox.add_node(node, false, c->is_lat_lon() ); // Si la reprojection WMS n'est pas activée, nous n'exposons que la bbox en projection native - if (! service->reprojection_enabled()) { + if (! services->map_reprojection) { break; } } - if (! service->reprojection_enabled()) { - for ( unsigned int i = 0; i < service->get_available_crs()->size(); i++ ) { - CRS* crs = service->get_available_crs()->at(i); + if (services->map_reprojection) { + for ( unsigned int i = 0; i < services->get_map_available_crs()->size(); i++ ) { + CRS* crs = services->get_map_available_crs()->at(i); BoundingBox bbox ( 0,0,0,0 ); if ( geographic_bbox.is_in_crs_area(crs)) { bbox = geographic_bbox; @@ -910,9 +917,9 @@ void Layer::add_node_tms(ptree& parent, TmsService* service) { node.add(".href", service->get_endpoint_uri() + "/1.0.0/" + id); } -json11::Json Layer::to_json_tiles(TilesService* service) { +json11::Json Layer::to_json_ogcapi(OgcApiService* service) { - if (! tiles) { + if (! ogcapi) { return json11::Json::NUL; } @@ -920,7 +927,7 @@ json11::Json Layer::to_json_tiles(TilesService* service) { { "id", id }, { "title", title }, { "description", abstract }, - { "extent", geographic_bbox.to_json_tiles() } + { "extent", geographic_bbox.to_json_ogcapi() } }; std::vector links; @@ -933,106 +940,95 @@ json11::Json Layer::to_json_tiles(TilesService* service) { }); for ( Metadata m : metadata) { - links.push_back(m.to_json_tiles("Dataset metadata", "describedby")); + links.push_back(m.to_json_ogcapi("Dataset metadata", "describedby")); } - if (Rok4Format::is_raster(pyramid->get_format())) { - links.push_back(json11::Json::object { - { "href", service->get_endpoint_uri() + "/collections/" + id + "/styles?f=json"}, - { "rel", "describedby"}, - { "type", "application/json"}, - { "title", "Styles list for " + id} - }); - } else { - links.push_back(json11::Json::object { - { "href", service->get_endpoint_uri() + "/collections/" + id + "/tiles?f=json"}, - { "rel", "describedby"}, - { "type", "application/json"}, - { "title", "Tilesets list for " + id} - }); - } - - res["links"] = links; - - res["crs"] = json11::Json::array { - pyramid->get_tms()->get_crs()->get_url() - }; - - if (Rok4Format::is_raster(pyramid->get_format())) { + if (raster) { res["dataType"] = "map"; res["dataTiles"] = false; - res["mapTiles"] = true; + if (service->tiles_enabled()) { + links.push_back(json11::Json::object { + { "href", service->get_endpoint_uri() + "/collections/" + id + "/map/tiles?f=json"}, + { "rel", "describedby"}, + { "type", "application/json"}, + { "title", "Tilesets list for " + id} + }); + res["mapTiles"] = true; + } else { + res["mapTiles"] = false; + } + if (service->maps_enabled()) { + links.push_back(json11::Json::object { + { "href", service->get_endpoint_uri() + "/collections/" + id + "/map?f={format}"}, + { "rel", "map"}, + { "type", "application/octet-stream"}, + { "title", id + " as raster map with default style"}, + { "templated", true} + }); + + // Lien vers l'image, pour chaque style disponible + for(auto const& s: available_styles) { + links.push_back(json11::Json::object { + { "href", service->get_endpoint_uri() + "/collections/" + id + "/styles/" + s->get_identifier() + "/map?f={format}"}, + { "rel", "map"}, + { "type", "application/octet-stream"}, + { "title", id + " as raster map with style " + s->get_identifier()}, + { "templated", true} + }); + } + } } else { res["dataType"] = "vector"; - res["dataTiles"] = true; - res["mapTiles"] = false; + res["mapTiles"] = false; + if (service->tiles_enabled()) { + links.push_back(json11::Json::object { + { "href", service->get_endpoint_uri() + "/collections/" + id + "/tiles?f=json"}, + { "rel", "describedby"}, + { "type", "application/json"}, + { "title", "Tilesets list for " + id} + }); + res["dataTiles"] = true; + } else { + res["dataTiles"] = false; + } } - res["minCellSize"] = pyramid->get_lowest_level()->get_res(); - res["maxCellSize"] = pyramid->get_highest_level()->get_res(); - - return res; -} - - -json11::Json Layer::to_json_styles(TilesService* service) { + res["links"] = links; - if (! tiles) { - return json11::Json::NUL; + if (attribution != NULL) { + res["attribution"] = attribution->get_title(); } - json11::Json::object res = json11::Json::object { - { "id", id }, - { "title", title }, - { "links", json11::Json::array { - json11::Json::object { - { "href", service->get_endpoint_uri() + "/collections/" + id + "/styles?f=json"}, - { "rel", "self"}, - { "type", "application/json"}, - { "title", "this document"} - } - }} + res["crs"] = json11::Json::array { + pyramid->get_tms()->get_crs()->get_url() }; - std::vector json_styles; - for ( Style* s : available_styles) { - json_styles.push_back(json11::Json::object { - { "id", s->get_identifier()}, - { "title", s->get_titles().at(0)}, - { "links", json11::Json::array { - json11::Json::object { - { "href", service->get_endpoint_uri() + "/collections/" + id + "/styles/" + s->get_identifier() + "/map/tiles?f=json"}, - { "rel", "describedby"}, - { "type", "application/json"}, - { "title", "Tilesets list for " + id + " with style " + s->get_identifier()} - } - }} - }); - } + res["storageCrs"] = pyramid->get_tms()->get_crs()->get_url(); - res["styles"] = json_styles; + res["minCellSize"] = pyramid->get_lowest_level()->get_res(); + res["maxCellSize"] = pyramid->get_highest_level()->get_res(); return res; } -json11::Json Layer::to_json_tilesets(TilesService* service, Style* style) { +json11::Json Layer::to_json_tilesets(OgcApiService* service) { json11::Json::object res = json11::Json::object {}; std::vector links; - if (style == NULL) { - // Interrogation de donnée vecteur + if (raster) { + // Interrogation de donnée raster links.push_back(json11::Json::object { - { "href", service->get_endpoint_uri() + "/collections/" + id + "/tiles?f=json"}, + { "href", service->get_endpoint_uri() + "/collections/" + id + "/map/tiles?f=json"}, { "rel", "self"}, { "type", "application/json"}, { "title", "this document"} }); } else { - // Interrogation de donnée raster + // Interrogation de donnée vecteur links.push_back(json11::Json::object { - { "href", service->get_endpoint_uri() + "/collections/" + id + "/styles/" + style->get_identifier() + "/map/tiles?f=json"}, + { "href", service->get_endpoint_uri() + "/collections/" + id + "/tiles?f=json"}, { "rel", "self"}, { "type", "application/json"}, { "title", "this document"} @@ -1047,12 +1043,12 @@ json11::Json Layer::to_json_tilesets(TilesService* service, Style* style) { std::string data_type; std::string tileset_uri; - if (style == NULL) { + if (raster) { + data_type = "map"; + tileset_uri = service->get_endpoint_uri() + "/collections/" + id + "/map/tiles/" + t->tms->get_id() + "?f=json"; + } else { data_type = "vector"; tileset_uri = service->get_endpoint_uri() + "/collections/" + id + "/tiles/" + t->tms->get_id() + "?f=json"; - } else { - data_type = "map"; - tileset_uri = service->get_endpoint_uri() + "/collections/" + id + "/styles/" + style->get_identifier() + "/map/tiles/" + t->tms->get_id() + "?f=json"; } tilesets.push_back(json11::Json::object { @@ -1070,8 +1066,8 @@ json11::Json Layer::to_json_tilesets(TilesService* service, Style* style) { }} }); - // Si la reprojection API Tiles n'est pas activée, nous n'exposons que le premier TMS, celui natif - if (! service->reprojection_enabled()) { + // Si la reprojection tuilée n'est pas activée ou que c'est de la donnée vecteur, nous n'exposons que le premier TMS, celui natif + if (! services->tile_reprojection || ! raster) { break; } } @@ -1081,7 +1077,7 @@ json11::Json Layer::to_json_tilesets(TilesService* service, Style* style) { return res; } -json11::Json Layer::to_json_tileset(TilesService* service, Style* style, TileMatrixSetInfos* tmsi) { +json11::Json Layer::to_json_tileset(OgcApiService* service, TileMatrixSetInfos* tmsi) { json11::Json::object res = json11::Json::object { { "title", title}, @@ -1092,38 +1088,41 @@ json11::Json Layer::to_json_tileset(TilesService* service, Style* style, TileMat std::vector links; - if (style == NULL) { - // Interrogation de donnée vecteur - res["dataType"] = "vector"; + if (raster) { + // Interrogation de donnée raster + res["dataType"] = "map"; links.push_back(json11::Json::object { - { "href", service->get_endpoint_uri() + "/collections/" + id + "/tiles/" + tmsi->tms->get_id() + "?f=json"}, + { "href", service->get_endpoint_uri() + "/collections/" + id + "/map/tiles/" + tmsi->tms->get_id() + "?f=json"}, { "rel", "self"}, { "type", "application/json"}, { "title", "this document"} }); - // Lien vers la tuile - links.push_back(json11::Json::object { - { "href", service->get_endpoint_uri() + "/collections/" + id + "/tiles/" + tmsi->tms->get_id() + "/{tileMatrix}/{tileRow}/{tileCol}?f=" + Rok4Format::to_tiles_format(pyramid->get_format())}, - { "rel", "item"}, - { "type", Rok4Format::to_mime_type(pyramid->get_format())}, - { "title", id + " tiles as " + Rok4Format::to_mime_type(pyramid->get_format())}, - { "templated", true} - }); + // Lien vers la tuile, pour chaque style disponible + for(auto const& s: available_styles) { + links.push_back(json11::Json::object { + { "href", service->get_endpoint_uri() + "/collections/" + id + "/styles/" + s->get_identifier() + "/map/tiles/" + tmsi->tms->get_id() + "/{tileMatrix}/{tileRow}/{tileCol}?f=" + Rok4Format::to_ogcapi_format(pyramid->get_format())}, + { "rel", "tiles"}, + { "type", Rok4Format::to_mime_type(pyramid->get_format())}, + { "title", id + " as raster tile with style " + s->get_identifier()}, + { "templated", true} + }); + } + } else { - // Interrogation de donnée raster - res["dataType"] = "map"; + // Interrogation de donnée vecteur + res["dataType"] = "vector"; links.push_back(json11::Json::object { - { "href", service->get_endpoint_uri() + "/collections/" + id + "/styles/" + style->get_identifier() + "/map/tiles/" + tmsi->tms->get_id() + "?f=json"}, + { "href", service->get_endpoint_uri() + "/collections/" + id + "/tiles/" + tmsi->tms->get_id() + "?f=json"}, { "rel", "self"}, { "type", "application/json"}, { "title", "this document"} }); // Lien vers la tuile links.push_back(json11::Json::object { - { "href", service->get_endpoint_uri() + "/collections/" + id + "/styles/" + style->get_identifier() + "/map/tiles/" + tmsi->tms->get_id() + "/{tileMatrix}/{tileRow}/{tileCol}?f=" + Rok4Format::to_tiles_format(pyramid->get_format())}, - { "rel", "item"}, + { "href", service->get_endpoint_uri() + "/collections/" + id + "/tiles/" + tmsi->tms->get_id() + "/{tileMatrix}/{tileRow}/{tileCol}?f=" + Rok4Format::to_ogcapi_format(pyramid->get_format())}, + { "rel", "tiles"}, { "type", Rok4Format::to_mime_type(pyramid->get_format())}, - { "title", id + " tiles as " + Rok4Format::to_mime_type(pyramid->get_format())}, + { "title", id + " as vector tile"}, { "templated", true} }); } @@ -1199,7 +1198,7 @@ std::string Layer::get_description_tilejson(TmsService* service) { }; - if (! Rok4Format::is_raster(pyramid->get_format())) { + if (! raster) { std::vector items; for (int i = 0; i < tables_names.size(); i++) { items.push_back(tables_infos.at(tables_names.at(i))->to_json(maxs.at(tables_names.at(i)),mins.at(tables_names.at(i)))); diff --git a/src/configurations/Layer.h b/src/configurations/Layer.h index 321f19a..4ccdaee 100644 --- a/src/configurations/Layer.h +++ b/src/configurations/Layer.h @@ -61,13 +61,14 @@ using boost::property_tree::ptree; #include #include "configurations/Server.h" +#include "configurations/Services.h" #include "configurations/Metadata.h" #include "configurations/Attribution.h" #include "services/wmts/Service.h" #include "services/wms/Service.h" #include "services/tms/Service.h" -#include "services/tiles/Service.h" +#include "services/ogcapi/Service.h" struct TileMatrixSetInfos { TileMatrixSet* tms; @@ -109,6 +110,11 @@ struct TileMatrixSetInfos { class Layer : public Configuration { private: + /** + * \~french \brief Configuration des services + * \~english \brief Services configuration + */ + ServicesConfiguration* services; /** * \~french \brief Identifiant de la couche * \~english \brief Layer identifier @@ -151,10 +157,10 @@ class Layer : public Configuration { */ bool tms; /** - * \~french \brief Autorisation de API Tiles pour ce layer - * \~english \brief Authorized API Tiles for this layer + * \~french \brief Autorisation des OGC API pour ce layer + * \~english \brief Authorized OGC API for this layer */ - bool tiles; + bool ogcapi; /** * \~french \brief Liste des mots-clés * \~english \brief List of keywords @@ -189,6 +195,12 @@ class Layer : public Configuration { /******************* PYRAMIDE RASTER *********************/ + /** + * \~french \brief Donnée image + * \~english \brief Raster data + */ + bool raster; + /** * \~french \brief Liste des styles associés * \~english \brief Linked styles list @@ -207,8 +219,8 @@ class Layer : public Configuration { std::vector available_tilematrixsets; /** - * \~french \brief Interpolation utilisée pour reprojeter ou recadrer les tuiles - * \~english \brief Interpolation used for resizing and reprojecting tiles + * \~french \brief Interpolation utilisée pour reprojeter ou recadrer les données raster + * \~english \brief Interpolation used for resizing and reprojecting raster */ Interpolation::KernelType resampling; /** @@ -246,7 +258,7 @@ class Layer : public Configuration { void calculate_native_tilematrix_limits(); void calculate_tilematrix_limits(); - bool parse(json11::Json& doc, ServicesConfiguration* services); + bool parse(json11::Json& doc); public: /** @@ -316,13 +328,13 @@ class Layer : public Configuration { bool is_tms_enabled() ; /** * \~french - * \brief Retourne le droit d'utiliser le service API Tiles - * \return tiles + * \brief Retourne le droit d'utiliser les services OGC API + * \return ogcapi * \~english - * \brief Return the right to use API Tiles - * \return tiles + * \brief Return the right to use OGC API + * \return ogcapi */ - bool is_tiles_enabled() ; + bool is_ogcapi_enabled() ; /** * \~french * \brief Retourne le droit d'utiliser un service WMTS @@ -337,6 +349,13 @@ class Layer : public Configuration { * \brief Return WMTS Inspire compliance */ bool is_wmts_inspire() ; + /** + * \~french + * \brief Retourne le type de donnée + * \~english + * \brief Return the data type + */ + bool is_raster() ; /** * \~french * \brief Retourne la liste des mots-clés @@ -577,36 +596,28 @@ class Layer : public Configuration { void add_node_wmts(ptree& parent, WmtsService* service, bool only_inspire, std::map< std::string, TileMatrixSetInfos*>* used_tms_list); /** - * \~french \brief Récupère la description OGC API Tiles de la couche au format JSON - * \param[in] service Service OGC API Tiles appelant - * \~english \brief Get layer OGC API Tiles description as JSON - * \param[in] service Calling OGC API Tiles service - */ - json11::Json to_json_tiles(TilesService* service); - - /** - * \~french \brief Récupère la description OGC API Tiles des styles disponibles de la couche au format JSON - * \param[in] service Service OGC API Tiles appelant - * \~english \brief Get available styles OGC API Tiles description for the layer as JSON - * \param[in] service Calling OGC API Tiles service + * \~french \brief Récupère la description OGC API de la couche au format JSON + * \param[in] service Service OGC API appelant + * \~english \brief Get layer OGC API description as JSON + * \param[in] service Calling OGC API service */ - json11::Json to_json_styles(TilesService* service); + json11::Json to_json_ogcapi(OgcApiService* service); /** - * \~french \brief Récupère la description OGC API Tiles des TMS disponibles de la couche au format JSON - * \param[in] service Service OGC API Tiles appelant - * \~english \brief Get available TMS OGC API Tiles description for the layer as JSON - * \param[in] service Calling OGC API Tiles service + * \~french \brief Récupère la description OGC API des TMS disponibles de la couche au format JSON + * \param[in] service Service OGC API appelant + * \~english \brief Get available TMS OGC API description for the layer as JSON + * \param[in] service Calling OGC API service */ - json11::Json to_json_tilesets(TilesService* service, Style* style); + json11::Json to_json_tilesets(OgcApiService* service); /** - * \~french \brief Récupère la description OGC API Tiles de la couche pour un TMS en particulier au format JSON - * \param[in] service Service OGC API Tiles appelant - * \~english \brief Get layer OGC API Tiles description for an available TMS as JSON - * \param[in] service Calling OGC API Tiles service + * \~french \brief Récupère la description OGC API de la couche pour un TMS en particulier au format JSON + * \param[in] service Service OGC API appelant + * \~english \brief Get layer OGC API description for an available TMS as JSON + * \param[in] service Calling OGC API service */ - json11::Json to_json_tileset(TilesService* service, Style* style, TileMatrixSetInfos* tmsi); + json11::Json to_json_tileset(OgcApiService* service, TileMatrixSetInfos* tmsi); /** * \~french \brief Récupère la description TileJSON de la couche au format JSON diff --git a/src/configurations/Metadata.h b/src/configurations/Metadata.h index 41ae377..855ca97 100644 --- a/src/configurations/Metadata.h +++ b/src/configurations/Metadata.h @@ -208,7 +208,7 @@ class Metadata : public ResourceLocator { node.add(".xlink:href", href); } - json11::Json to_json_tiles(std::string title, std::string rel) const { + json11::Json to_json_ogcapi(std::string title, std::string rel) const { return json11::Json::object { { "href", href }, { "type", type }, diff --git a/src/configurations/Server.cpp b/src/configurations/Server.cpp index 6a3ba69..e162f87 100644 --- a/src/configurations/Server.cpp +++ b/src/configurations/Server.cpp @@ -151,16 +151,6 @@ bool ServerConfiguration::parse(json11::Json& doc) { backlog = doc["backlog"].int_value(); } - // enabled - if (doc["enabled"].is_null()) { - enabled = true; - } else if (! doc["enabled"].is_bool()) { - error_message = "enabled have to be a boolean"; - return false; - } else { - enabled = doc["enabled"].bool_value(); - } - // configurations json11::Json configurationsSection = doc["configurations"]; if (configurationsSection.is_null()) { @@ -237,10 +227,6 @@ ServerConfiguration::ServerConfiguration(std::string path) : Configuration(path) ServerConfiguration::~ServerConfiguration(){ - // Les couches - std::map::iterator itLay; - for ( itLay = layers.begin(); itLay != layers.end(); itLay++ ) - delete itLay->second; } @@ -252,30 +238,7 @@ std::string ServerConfiguration::get_log_file_prefix() {return log_file_prefix;} boost::log::v2_mt_posix::trivial::severity_level ServerConfiguration::get_log_level() {return log_level;} std::string ServerConfiguration::get_services_configuration_file() {return services_configuration_file;} - -std::map& ServerConfiguration::get_layers() {return layers;} std::string ServerConfiguration::get_layers_list() {return layers_list;} -void ServerConfiguration::add_layer(Layer* l) { - layers.insert ( std::pair ( l->get_id(), l ) ); -} -int ServerConfiguration::get_layers_count() { - return layers.size(); -} -Layer* ServerConfiguration::get_layer(std::string id) { - std::map::iterator itLay = layers.find ( id ); - if ( itLay == layers.end() ) { - return NULL; - } - return itLay->second; -} -void ServerConfiguration::delete_layer(std::string id) { - std::map::iterator itLay = layers.find ( id ); - if ( itLay != layers.end() ) { - delete itLay->second; - layers.erase(itLay); - } -} int ServerConfiguration::get_threads_count() {return threads_count;} std::string ServerConfiguration::get_socket() {return socket;} -bool ServerConfiguration::is_enabled() {return enabled;} diff --git a/src/configurations/Server.h b/src/configurations/Server.h index da20946..e20638e 100644 --- a/src/configurations/Server.h +++ b/src/configurations/Server.h @@ -56,7 +56,7 @@ class ServerConfiguration; #include #include "configurations/Layer.h" -#include "Rok4Server.h" +#include "core/Rok4Server.h" #include "config.h" @@ -68,29 +68,18 @@ class ServerConfiguration; class ServerConfiguration : public Configuration { friend class Rok4Server; - friend class CommonService; - friend class TmsService; public: ServerConfiguration(std::string path); ~ServerConfiguration(); - bool is_enabled(); - std::string get_log_output() ; int get_log_file_period() ; std::string get_log_file_prefix() ; boost::log::v2_mt_posix::trivial::severity_level get_log_level() ; std::string get_services_configuration_file() ; - std::string get_layers_list() ; - std::map& get_layers() ; - void add_layer(Layer* l) ; - void delete_layer(std::string id) ; - int get_layers_count() ; - Layer* get_layer(std::string id) ; - int get_threads_count() ; std::string get_socket() ; @@ -122,11 +111,6 @@ class ServerConfiguration : public Configuration * \~english \brief File or object containing layers' descriptors list */ std::string layers_list; - /** - * \~french \brief Liste des couches disponibles - * \~english \brief Available layers list - */ - std::map layers; /** * \~french \brief Adresse du socket d'écoute (vide si lancement géré par un tiers) @@ -139,12 +123,6 @@ class ServerConfiguration : public Configuration */ int backlog; - /** - * \~french \brief Définit si le serveur doit honorer les requêtes de consultation - * \~english \brief Define whether broadcast request should be honored - */ - bool enabled; - private: bool parse(json11::Json& doc); diff --git a/src/configurations/Services.cpp b/src/configurations/Services.cpp index ba97d87..ccd2296 100644 --- a/src/configurations/Services.cpp +++ b/src/configurations/Services.cpp @@ -43,83 +43,301 @@ bool ServicesConfiguration::parse(json11::Json& doc) { /********************** Default values */ + enabled = true; + service_provider=""; fee=""; access_constraint=""; provider_site=""; default_style="normal"; + default_inspire=false; + + info_formats.push_back("text/plain"); + info_formats.push_back("text/xml"); + info_formats.push_back("text/html"); + info_formats.push_back("application/json"); + + map_reprojection = true; + tile_reprojection = false; + + map_max_layers_count = 1; + map_max_width = 5000; + map_max_height = 5000; + map_max_tile_x = 32; + map_max_tile_y = 32; + + map_formats.push_back("image/jpeg"); + map_formats.push_back("image/png"); + map_formats.push_back("image/tiff"); + map_formats.push_back("image/geotiff"); + map_formats.push_back("image/x-bil;bits=32"); + + + // ----------------------- enabled + if (doc["enabled"].is_bool()) { + enabled = doc["enabled"].bool_value(); + } else if (! doc["enabled"].is_null()) { + error_message = "Services configuration: enabled have to be a boolean"; + return false; + } // ----------------------- Global - if (doc["fee"].is_string()) { - fee = doc["fee"].string_value(); - } else if (! doc["fee"].is_null()) { - error_message = "Services configuration: fee have to be a string"; - return false; - } + if (doc["global"].is_object()) { - if (doc["access_constraint"].is_string()) { - access_constraint = doc["access_constraint"].string_value(); - } else if (! doc["access_constraint"].is_null()) { - error_message = "Services configuration: access_constraint have to be a string"; - return false; - } + json11::Json global_section = doc["global"]; - if (doc["provider"].is_string()) { - service_provider = doc["provider"].string_value(); - } else if (! doc["provider"].is_null()) { - error_message = "Services configuration: provider have to be a string"; - return false; - } + if (global_section["fee"].is_string()) { + fee = global_section["fee"].string_value(); + } else if (! global_section["fee"].is_null()) { + error_message = "Services configuration: global.fee have to be a string"; + return false; + } - if (doc["site"].is_string()) { - provider_site = doc["site"].string_value(); - } else if (! doc["site"].is_null()) { - error_message = "Services configuration: site have to be a string"; - return false; - } + if (global_section["access_constraint"].is_string()) { + access_constraint = global_section["access_constraint"].string_value(); + } else if (! global_section["access_constraint"].is_null()) { + error_message = "Services configuration: global.access_constraint have to be a string"; + return false; + } - if (doc["crs_equivalences"].is_string()) { - std::string crs_equivalences_file = doc["crs_equivalences"].string_value(); - if (! load_crs_equivalences(crs_equivalences_file)) { + if (global_section["provider"].is_string()) { + service_provider = global_section["provider"].string_value(); + } else if (! global_section["provider"].is_null()) { + error_message = "Services configuration: global.provider have to be a string"; return false; } - } else if (! doc["crs_equivalences"].is_null()) { - error_message = "crs_equivalences have to be a string"; - return false; - } - if (doc["default_style"].is_string()) { - default_style = doc["default_style"].string_value(); - } else if (! doc["default_style"].is_null()) { - error_message = "default_style have to be a string"; - return false; - } + if (global_section["site"].is_string()) { + provider_site = global_section["site"].string_value(); + } else if (! global_section["site"].is_null()) { + error_message = "Services configuration: global.site have to be a string"; + return false; + } - // ----------------------- Contact + if (global_section["crs_equivalences"].is_string()) { + std::string crs_equivalences_file = global_section["crs_equivalences"].string_value(); + if (! load_crs_equivalences(crs_equivalences_file)) { + return false; + } + } else if (! global_section["crs_equivalences"].is_null()) { + error_message = "Services configuration: global.crs_equivalences have to be a string"; + return false; + } - json11::Json contact_section = doc["contact"]; + if (global_section["default_style"].is_string()) { + default_style = global_section["default_style"].string_value(); + } else if (! global_section["default_style"].is_null()) { + error_message = "Services configuration: global.default_style have to be a string"; + return false; + } - contact = new Contact(contact_section); - if (! contact->is_ok()) { - error_message = "Services configuration: " + contact->get_error_message(); - return false; - } + // Contact + json11::Json contact_section = global_section["contact"]; - // ----------------------- Chargement des services + contact = new Contact(contact_section); + if (! contact->is_ok()) { + error_message = "Services configuration: " + contact->get_error_message(); + return false; + } + + // Inspire + if (global_section["inspire"].is_bool()) { + default_inspire = global_section["inspire"].bool_value(); + } else if (! global_section["inspire"].is_null()) { + error_message = "Services configuration: global.inspire have to be a boolean"; + return false; + } + + // Map + if (global_section["map"].is_object()) { + + json11::Json map_section = global_section["map"]; + + if (map_section["reprojection"].is_bool()) { + map_reprojection = map_section["reprojection"].bool_value(); + } else if (! map_section["reprojection"].is_null()) { + error_message = "Services configuration: global.map.reprojection have to be a boolean"; + return false; + } + + if (map_section["formats"].is_array()) { + map_formats.clear(); + for (json11::Json f : map_section["formats"].array_items()) { + if (f.is_string()) { + std::string format = f.string_value(); + if ( format != "image/jpeg" && + format != "image/png" && + format != "image/tiff" && + format != "image/geotiff" && + format != "image/x-bil;bits=32" && + format != "image/gif" && + format != "text/asc" ) { + error_message = "Services configuration: global.map.formats [" + format + "] is not an handled MIME format"; + return false; + } else { + map_formats.push_back ( format ); + } + } else { + error_message = "Services configuration: global.map.formats have to be a string array"; + return false; + } + } + } else if (! map_section["formats"].is_null()) { + error_message = "Services configuration: global.map.formats have to be a string array"; + return false; + } + + if (map_section["limits"].is_object()) { + if (map_section["limits"]["layers_count"].is_number() && map_section["limits"]["layers_count"].number_value() >= 1) { + map_max_layers_count = map_section["limits"]["layers_count"].number_value(); + } else if (! map_section["limits"]["layers_count"].is_null()) { + error_message = "Services configuration: global.map.limits.layers_count have to be an integer >= 1"; + return false; + } + + if (map_section["limits"]["width"].is_number() && map_section["limits"]["width"].number_value() >= 1) { + map_max_width = map_section["limits"]["width"].number_value(); + } else if (! map_section["limits"]["width"].is_null()) { + error_message = "Services configuration: global.map.limits.width have to be an integer >= 1"; + return false; + } + + if (map_section["limits"]["height"].is_number() && map_section["limits"]["height"].number_value() >= 1) { + map_max_height = map_section["limits"]["height"].number_value(); + } else if (! map_section["limits"]["height"].is_null()) { + error_message = "Services configuration: global.map.limits.height have to be an integer >= 1"; + return false; + } + + if (map_section["limits"]["tile_x"].is_number() && map_section["limits"]["tile_x"].number_value() >= 1) { + map_max_tile_x = map_section["limits"]["tile_x"].number_value(); + } else if (! map_section["limits"]["tile_x"].is_null()) { + error_message = "Services configuration: global.map.limits.tile_x have to be an integer >= 1"; + return false; + } - json11::Json common_section = doc["common"]; + if (map_section["limits"]["tile_y"].is_number() && map_section["limits"]["tile_y"].number_value() >= 1) { + map_max_tile_y = map_section["limits"]["tile_y"].number_value(); + } else if (! map_section["limits"]["tile_y"].is_null()) { + error_message = "Services configuration: global.map.limits.tile_y have to be an integer >= 1"; + return false; + } + + } else if (! map_section["limits"].is_null()) { + error_message = "Services configuration: global.map.limits have to be an object"; + return false; + } + + + bool crs84_present = false; + if (map_reprojection && map_section["crs"].is_array()) { + for (json11::Json c : map_section["crs"].array_items()) { + if (c.is_string()) { + std::string crs_string = c.string_value(); + + CRS* crs = CrsBook::get_crs( crs_string ); + if ( ! crs->is_define() ) { + BOOST_LOG_TRIVIAL(warning) << "The (WMS) CRS [" << crs_string <<"] is not present in PROJ" ; + continue; + } + + BOOST_LOG_TRIVIAL(info) << "Adding global CRS " << crs->get_request_code() ; + map_crss.push_back(crs); + if (crs->get_request_code() == "CRS:84") { + crs84_present = true; + } + + if (handle_crs_equivalences()) { + std::vector eqs = get_equals_crs(crs->get_request_code()); + size_t init_size = map_crss.size(); + for (unsigned int e = 0; e < eqs.size(); e++) { + bool already_in = false; + for ( int i = 0; i < init_size ; i++ ) { + if (map_crss.at( i )->cmp_request_code(eqs.at(e)->get_request_code() ) ){ + already_in = true; + break; + } + } + if (! already_in) { + BOOST_LOG_TRIVIAL(info) << "Adding equivalent global CRS [" << eqs.at(e)->get_request_code() <<"] of [" << crs->get_request_code() << "]" ; + map_crss.push_back(eqs.at(e)); + if (eqs.at(e)->get_request_code() == "CRS:84") { + crs84_present = true; + } + } + } + } + } else { + error_message = "WMS service: crs have to be a string array"; + return false; + } + } + } else if (! map_section["crs"].is_null()) { + error_message = "WMS service: crs have to be a string array with enabled reprojection"; + return false; + } + + if (! crs84_present) { + BOOST_LOG_TRIVIAL(info) << "CRS:84 not found -> adding global CRS CRS:84" ; + CRS* crs = CrsBook::get_crs( "CRS:84" ); + + if ( ! crs->is_define() ) { + error_message = "WMS service: The CRS [CRS:84] is not present in PROJ" ; + return false; + } + + map_crss.push_back ( crs ); + + if (handle_crs_equivalences()) { + std::vector eqs = get_equals_crs(crs->get_request_code()); + size_t init_size = map_crss.size(); + for (unsigned int e = 0; e < eqs.size(); e++) { + bool already_in = false; + for ( int i = 0; i < init_size ; i++ ) { + if (map_crss.at( i )->cmp_request_code(eqs.at(e)->get_request_code() ) ){ + already_in = true; + } + } + if (! already_in) { + BOOST_LOG_TRIVIAL(info) << "Adding equivalent global CRS [" << eqs.at(e)->get_request_code() <<"] of [CRS:84]" ; + map_crss.push_back(eqs.at(e)); + } + } + } + } + + } else if (! global_section["map"].is_null()) { + error_message = "Services configuration: global.map have to be an object"; + return false; + } + + // Tiles + + + if (global_section["tile"].is_object()) { + + json11::Json tile_section = global_section["tile"]; + + if (tile_section["reprojection"].is_bool()) { + tile_reprojection = tile_section["reprojection"].bool_value(); + } else if (! tile_section["reprojection"].is_null()) { + error_message = "Services configuration: global.tile.reprojection have to be a boolean"; + return false; + } + + + } else if (! global_section["tile"].is_null()) { + error_message = "Services configuration: global.tile have to be an object"; + return false; + } - common_service = new CommonService(common_section); - if (! common_service->is_ok()) { - error_message = "Services configuration: " + common_service->get_error_message(); + } else if (! doc["global"].is_null()) { + error_message = "Services configuration: global have to be an object"; return false; } - if (common_service->is_enabled()) { - BOOST_LOG_TRIVIAL(info) << "COMMON service enabled"; - } else { - BOOST_LOG_TRIVIAL(info) << "COMMON service disabled"; - } + + // ----------------------- Chargement des services json11::Json health_section = doc["health"]; @@ -168,9 +386,9 @@ bool ServicesConfiguration::parse(json11::Json& doc) { return false; } if (wms_service->is_enabled()) { - BOOST_LOG_TRIVIAL(info) << "WMS service enabled"; + BOOST_LOG_TRIVIAL(info) << "Services configuration enabled"; } else { - BOOST_LOG_TRIVIAL(info) << "WMS service disabled"; + BOOST_LOG_TRIVIAL(info) << "Services configuration disabled"; } json11::Json admin_section = doc["admin"]; @@ -186,17 +404,17 @@ bool ServicesConfiguration::parse(json11::Json& doc) { BOOST_LOG_TRIVIAL(info) << "ADMIN service disabled"; } - json11::Json tiles_section = doc["tiles"]; + json11::Json ogcapi_section = doc["ogcapi"]; - tiles_service = new TilesService(tiles_section); - if (! tiles_service->is_ok()) { - error_message = "Services configuration: " + tiles_service->get_error_message(); + ogcapi_service = new OgcApiService(ogcapi_section); + if (! ogcapi_service->is_ok()) { + error_message = "Services configuration: " + ogcapi_service->get_error_message(); return false; } - if (tiles_service->is_enabled()) { - BOOST_LOG_TRIVIAL(info) << "TILES service enabled"; + if (ogcapi_service->is_enabled()) { + BOOST_LOG_TRIVIAL(info) << "OGC API service enabled"; } else { - BOOST_LOG_TRIVIAL(info) << "TILES service disabled"; + BOOST_LOG_TRIVIAL(info) << "OGC API service disabled"; } return true; @@ -319,25 +537,79 @@ bool ServicesConfiguration::are_crs_equals( std::string crs1, std::string crs2 ) return false; } -std::string ServicesConfiguration::get_default_style_id() { - return default_style; +bool ServicesConfiguration::is_available_infoformat(std::string f) { + return (std::find(info_formats.begin(), info_formats.end(), f) != info_formats.end()); +} + +std::vector* ServicesConfiguration::get_available_infoformats() { + return &info_formats; +} + + +bool ServicesConfiguration::is_map_available_crs(CRS* c) { + return is_map_available_crs(c->get_request_code()); +} +bool ServicesConfiguration::is_map_available_crs(std::string c) { + if (! map_reprojection) { + return false; + } + for ( unsigned int k = 0; k < map_crss.size(); k++ ) { + if ( map_crss.at (k)->cmp_request_code ( c ) ) { + return true; + } + } + return false; +} + +bool ServicesConfiguration::is_map_available_format(std::string f) { + return (std::find(map_formats.begin(), map_formats.end(), f) != map_formats.end()); +} + +std::vector* ServicesConfiguration::get_map_available_crs() { + return &map_crss; } ServicesConfiguration::~ServicesConfiguration(){ - delete common_service; delete tms_service; delete health_service; delete wmts_service; delete wms_service; delete admin_service; - delete tiles_service; + delete ogcapi_service; delete contact; + + // Les couches + std::map::iterator itLay; + for ( itLay = layers.begin(); itLay != layers.end(); itLay++ ) + delete itLay->second; } +bool ServicesConfiguration::is_enabled() {return enabled;} + void ServicesConfiguration::clean_cache() { wms_service->clean_cache(); wmts_service->clean_cache(); tms_service->clean_cache(); - common_service->clean_cache(); - tiles_service->clean_cache(); -}; \ No newline at end of file + ogcapi_service->clean_cache(); +}; +std::map& ServicesConfiguration::get_layers() {return layers;} +void ServicesConfiguration::add_layer(Layer* l) { + layers.insert ( std::pair ( l->get_id(), l ) ); +} +int ServicesConfiguration::get_layers_count() { + return layers.size(); +} +Layer* ServicesConfiguration::get_layer(std::string id) { + std::map::iterator itLay = layers.find ( id ); + if ( itLay == layers.end() ) { + return NULL; + } + return itLay->second; +} +void ServicesConfiguration::delete_layer(std::string id) { + std::map::iterator itLay = layers.find ( id ); + if ( itLay != layers.end() ) { + delete itLay->second; + layers.erase(itLay); + } +} \ No newline at end of file diff --git a/src/configurations/Services.h b/src/configurations/Services.h index cc68568..3b78efe 100644 --- a/src/configurations/Services.h +++ b/src/configurations/Services.h @@ -52,15 +52,14 @@ #include #include -#include "Rok4Server.h" +#include "core/Rok4Server.h" #include "configurations/Metadata.h" #include "configurations/Contact.h" -#include "services/common/Service.h" #include "services/health/Service.h" #include "services/tms/Service.h" #include "services/wmts/Service.h" #include "services/wms/Service.h" -#include "services/tiles/Service.h" +#include "services/ogcapi/Service.h" #include "services/admin/Service.h" #include "config.h" @@ -73,23 +72,33 @@ class ServicesConfiguration : public Configuration { friend class Rok4Server; + friend class Layer; + friend class AdminService; + friend class HealthService; friend class WmtsService; friend class TmsService; friend class WmsService; - friend class TilesService; + friend class OgcApiService; public: ServicesConfiguration(std::string path); ~ServicesConfiguration(); - CommonService* get_common_service() {return common_service;}; + bool is_enabled(); + HealthService* get_health_service() {return health_service;}; TmsService* get_tms_service() {return tms_service;}; WmtsService* get_wmts_service() {return wmts_service;}; WmsService* get_wms_service() {return wms_service;}; AdminService* get_admin_service() {return admin_service;}; - TilesService* get_tiles_service() {return tiles_service;}; + OgcApiService* get_ogcapi_service() {return ogcapi_service;}; + + std::map& get_layers() ; + void add_layer(Layer* l) ; + void delete_layer(std::string id) ; + int get_layers_count() ; + Layer* get_layer(std::string id) ; /** * \~french @@ -103,7 +112,58 @@ class ServicesConfiguration : public Configuration }; bool are_crs_equals( std::string crs1, std::string crs2 ); - std::string get_default_style_id(); + /** + * \~french + * \brief Teste la validité du info format + * \~english + * \brief Test if info format is valid + */ + bool is_available_infoformat(std::string f) ; + + /** + * \~french + * \brief Liste des formats d'information des services + * \~english + * \brief Services informations formats + */ + std::vector* get_available_infoformats() ; + + /** + * \~french + * \brief Teste la présence du CRS dans la liste + * \return Présent ou non + * \~english + * \brief Test if CRS is in the CRS list + * \return Present or not + */ + bool is_map_available_crs(CRS* c) ; + + /** + * \~french + * \brief Teste la présence du CRS dans la liste + * \return Présent ou non + * \~english + * \brief Test if CRS is in the CRS list + * \return Present or not + */ + bool is_map_available_crs(std::string c) ; + + /** + * \~french + * \brief Teste la validité du format + * \~english + * \brief Test if format is valid + */ + bool is_map_available_format(std::string f) ; + + /** + * \~french + * \brief Liste des CRS globaux du service + * \~english + * \brief Global service CRS list + */ + std::vector* get_map_available_crs() ; + /** * \~french @@ -115,6 +175,18 @@ class ServicesConfiguration : public Configuration protected: + /** + * \~french \brief Liste des couches disponibles + * \~english \brief Available layers list + */ + std::map layers; + + /** + * \~french \brief Activation générale des services + * \~english \brief Global activation for services + */ + bool enabled; + // ----------------------- Global std::string service_provider; @@ -125,6 +197,23 @@ class ServicesConfiguration : public Configuration Contact* contact; std::string default_style; + bool default_inspire; + std::vector info_formats; + + // Map + bool map_reprojection; + std::vector map_formats; + + int map_max_layers_count; + int map_max_width; + int map_max_height; + int map_max_tile_x; + int map_max_tile_y; + + std::vector map_crss; + + // Tile + bool tile_reprojection; private: @@ -138,13 +227,12 @@ class ServicesConfiguration : public Configuration bool parse(json11::Json& doc); - CommonService* common_service; HealthService* health_service; TmsService* tms_service; WmtsService* wmts_service; WmsService* wms_service; AdminService* admin_service; - TilesService* tiles_service; + OgcApiService* ogcapi_service; std::map > crs_equivalences; }; diff --git a/src/DataStreams.h b/src/core/DataStreams.h similarity index 99% rename from src/DataStreams.h rename to src/core/DataStreams.h index 98b7dec..4dbaa45 100644 --- a/src/DataStreams.h +++ b/src/core/DataStreams.h @@ -36,7 +36,7 @@ */ /** - * \file DataStreams.h + * \file core/DataStreams.h * \~french * \brief Définition des classes EmptyResponseDataStream et MessageDataStream * \~english diff --git a/src/Inspire.cpp b/src/core/Inspire.cpp similarity index 99% rename from src/Inspire.cpp rename to src/core/Inspire.cpp index f411d20..30aa123 100644 --- a/src/Inspire.cpp +++ b/src/core/Inspire.cpp @@ -47,7 +47,7 @@ #include #include -#include "Inspire.h" +#include "core/Inspire.h" namespace Inspire { diff --git a/src/Inspire.h b/src/core/Inspire.h similarity index 100% rename from src/Inspire.h rename to src/core/Inspire.h diff --git a/src/core/Map.h b/src/core/Map.h new file mode 100644 index 0000000..3aa6b20 --- /dev/null +++ b/src/core/Map.h @@ -0,0 +1,318 @@ +/* + * Copyright © (2011-2013) Institut national de l'information + * géographique et forestière + * + * Géoportail SAV + * + * This software is a computer program whose purpose is to publish geographic + * data using OGC WMS and WMTS protocol. + * + * This software is governed by the CeCILL-C license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL-C + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * + * knowledge of the CeCILL-C license and that you accept its terms. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "configurations/Layer.h" + +namespace Map { + +/** + * \~french + * \brief Retourne l'image demandée + * \return Flux de donnée + * \~english + * \brief Give the asked image + * \return Data stream + */ +static DataStream* get_map( + ServicesConfiguration* services, bool reprojection, int max_tile_x, int max_tile_y, + std::vector layers, int width, int height, CRS* crs, BoundingBox bbox, std::vector styles, + std::string format, std::map format_options, int dpi, std::string* error +) { + // Traitement de la requête + + std::vector images; + + // Le format des canaux sera identifié à partir des données en entrée, en prenant en compte le style + SampleFormat::eSampleFormat sample_format = SampleFormat::UNKNOWN; + int nodata; + + // Le nombre de canaux dans l'image finale sera égale au nombre maximum dans les données en entrée (en prenant en compte le style) + int bands = 0; + + for (int i = 0; i < layers.size(); i++) { + bool crs_equals = services->are_crs_equals(crs->get_request_code(), layers.at(i)->get_pyramid()->get_tms()->get_crs()->get_request_code()); + + if (!crs_equals && !reprojection) { + *error = "Reprojection is not available"; + return NULL; + } + + Style* style = styles.at(i); + + // On vérifie que toutes les images ont bien le même format de canal, après application du style + if (sample_format != SampleFormat::UNKNOWN && sample_format != style->get_sample_format(layers.at(i)->get_pyramid()->get_sample_format())) { + *error = "All layers (with their style) have to own the same sample format (int or float)"; + return NULL; + } else { + sample_format = style->get_sample_format(layers.at(i)->get_pyramid()->get_sample_format()); + + // Dans le cas d'un geotiff, on renseigne la valeur de nodata + // on ne peut mettre qu'une valeur, ce sera celle du premier canal du nodata de la première couche (après style) + nodata = *(style->get_output_nodata_value(layers.at(i)->get_pyramid()->get_nodata_value())); + } + + Image* image = layers.at(i)->get_pyramid()->getbbox(max_tile_x, max_tile_y, bbox, width, height, crs, crs_equals, layers.at(i)->get_resampling(), dpi); + + if (image == NULL) { + *error = "BBOX too big"; + return NULL; + } + + StyledImage* s_image = StyledImage::create(image, style); + image = s_image; + images.push_back(image); + + // Le nombre final de canaux est celui maxiumum parmis les couches, c'est à dire celui de la donnée en prenant en compte le style + bands = std::max(bands, image->get_channels()); + } + + // On construit la réponse finale, en superposant les couches + + Image* final_image; + + if (images.size() >= 2) { + int background_value[bands]; + memset(background_value, 0, bands * sizeof(int)); + final_image = MergeImage::create(images, bands, background_value, NULL, Merge::ALPHATOP); + } else { + final_image = images.at(0); + } + + final_image->set_bbox(bbox); + final_image->set_crs(crs); + + if (format == "image/png" && sample_format == SampleFormat::UINT8) { + return new PNGEncoder(final_image, NULL); + } else if (format == "image/tiff" || format == "image/geotiff") { + bool is_geotiff = (format == "image/geotiff"); + + std::map::iterator it = format_options.find("compression"); + std::string opt = ""; + if (it != format_options.end()) { + opt = it->second; + } + + if (sample_format == SampleFormat::UINT8) { + if (opt.compare("lzw") == 0) { + return new TiffLZWEncoder(final_image, is_geotiff, nodata); + } + if (opt.compare("deflate") == 0) { + return new TiffDeflateEncoder(final_image, is_geotiff, nodata); + } + if (opt.compare("raw") == 0 || opt == "") { + return new TiffRawEncoder(final_image, is_geotiff, nodata); + } + if (opt.compare("packbits") == 0) { + return new TiffPackBitsEncoder(final_image, is_geotiff, nodata); + } + } else if (sample_format == SampleFormat::FLOAT32) { + if (opt.compare("lzw") == 0) { + return new TiffLZWEncoder(final_image, is_geotiff, nodata); + } + if (opt.compare("deflate") == 0) { + return new TiffDeflateEncoder(final_image, is_geotiff, nodata); + } + if (opt.compare("raw") == 0 || opt == "") { + return new TiffRawEncoder(final_image, is_geotiff, nodata); + } + if (opt.compare("packbits") == 0) { + return new TiffPackBitsEncoder(final_image, is_geotiff, nodata); + } + } + + delete final_image; + *error = "Used data and expected format are not consistent"; + return NULL; + } else if (format == "image/jpeg" && sample_format == SampleFormat::UINT8 && bands == 3) { + std::map::iterator it = format_options.find("quality"); + int quality = 75; + if (it != format_options.end()) { + // si on n'arrive pas à paser en entier l'option, on remet 75 + if (sscanf(it->second.c_str(), "%d", &quality) != 1) quality = 75; + } + + return new JPEGEncoder(final_image, quality); + } else if (format == "image/x-bil;bits=32" && sample_format == SampleFormat::FLOAT32) { + return new BilEncoder(final_image); + } else if (format == "text/asc" && sample_format == SampleFormat::FLOAT32 && final_image->get_channels() == 1) { + return new AscEncoder(final_image); + } else { + delete final_image; + *error = "Used data format (" + std::to_string(bands) + " band(s) " + SampleFormat::to_string(sample_format) + ") and expected output format (" + format + ") are not consistent"; + return NULL; + } + return NULL; +} + +/** + * \~french + * \brief Retourne les informations du pixel demandé + * \return Flux de donnée + * \~english + * \brief Give the asked pixel's informations + * \return Data stream + */ +static DataStream* get_feature_info( + ServicesConfiguration* services, bool reprojection, int max_tile_x, int max_tile_y, + std::vector layers, std::vector query_layers, int width, int height, CRS* crs, BoundingBox bbox, std::string str_bbox, + std::vector styles, std::string format, std::map format_options, int dpi, + int i, int j, int feature_count, std::string info_format, + std::string* error +) { + + Layer* layer = query_layers.at(0); + + std::string gfi_type = layer->get_gfi_type(); + if (gfi_type.compare("PYRAMID") == 0) { + + // On cherche la valeur du pixel source sous le clique + bool crs_equals = services->are_crs_equals(crs->get_request_code(), layer->get_pyramid()->get_tms()->get_crs()->get_request_code()); + + if (! crs_equals && ! reprojection) { + *error = "Reprojection is not available"; + return NULL; + } + + Image* image = layer->get_pyramid()->getbbox(max_tile_x, max_tile_y, bbox, width, height, crs, crs_equals, layer->get_resampling(), dpi); + + if (image == NULL) { + *error = "BBOX too big"; + return NULL; + } + + std::vector gfi_data; + int bands = image->get_channels(); + switch (layer->get_pyramid()->get_format()) { + case Rok4Format::TIFF_RAW_UINT8: + case Rok4Format::TIFF_JPG_UINT8: + case Rok4Format::TIFF_PNG_UINT8: + case Rok4Format::TIFF_LZW_UINT8: + case Rok4Format::TIFF_ZIP_UINT8: + case Rok4Format::TIFF_PKB_UINT8: { + uint8_t* data = new uint8_t[image->get_width() * bands * sizeof(uint8_t)]; + image->get_line(data, j); + for (int b = 0; b < bands; b++) { + std::stringstream ss; + ss << (int)data[bands * i + b]; + gfi_data.push_back(ss.str()); + } + delete[] data; + break; + } + case Rok4Format::TIFF_RAW_FLOAT32: + case Rok4Format::TIFF_LZW_FLOAT32: + case Rok4Format::TIFF_ZIP_FLOAT32: + case Rok4Format::TIFF_PKB_FLOAT32: { + float* data = new float[image->get_width() * bands * sizeof(float)]; + image->get_line(data, j); + for (int b = 0; b < bands; b++) { + std::stringstream ss; + ss.setf(std::ios::fixed, std::ios::floatfield); + ss.precision(2); + ss << data[bands * i + b]; + gfi_data.push_back(ss.str()); + } + delete[] data; + break; + } + default: + *error = "No readable data found"; + return NULL; + } + + delete image; + + return Utils::format_get_feature_info(gfi_data, info_format); + } else if (gfi_type.compare("EXTERNALWMS") == 0) { + BOOST_LOG_TRIVIAL(debug) << "GFI sur WMS externe, en projection native ou non"; + + std::map query_params; + query_params.emplace("VERSION", "1.3.0"); + query_params.emplace("SERVICE", "WMS"); + query_params.emplace("REQUEST", "GetFeatureInfo"); + query_params.emplace("STYLES", ""); + query_params.emplace("LAYERS", layer->get_gfi_layers()); + query_params.emplace("QUERY_LAYERS", layer->get_gfi_query_layers()); + query_params.emplace("INFO_FORMAT", info_format); + query_params.emplace("FORMAT", "image/tiff"); + query_params.emplace("FEATURE_COUNT", std::to_string(feature_count)); + query_params.emplace("CRS", crs->get_request_code()); + query_params.emplace("WIDTH", std::to_string(width)); + query_params.emplace("HEIGHT", std::to_string(height)); + query_params.emplace("I", std::to_string(i)); + query_params.emplace("J", std::to_string(j)); + query_params.emplace("BBOX", str_bbox); + + std::map extra_query_params = layer->get_gfi_extra_params(); + query_params.insert(extra_query_params.begin(), extra_query_params.end()); + + Request* gfi_request = new Request("GET", layer->get_gfi_url(), query_params); + + RawDataStream* response = gfi_request->send(); + delete gfi_request; + + if (response == NULL) { + *error = "No readable data found"; + return NULL; + } + + return response; + } + + BOOST_LOG_TRIVIAL(error) << "Get Feature Info badly configured for layer" << layer->get_id(); + return NULL; +} + +}; // namespace Map diff --git a/src/services/health/Threads.cpp b/src/core/Process.cpp similarity index 81% rename from src/services/health/Threads.cpp rename to src/core/Process.cpp index ca4e133..c63f411 100644 --- a/src/services/health/Threads.cpp +++ b/src/core/Process.cpp @@ -36,11 +36,11 @@ */ /** - * \file services/health/Threads.cpp + * \file core/Process.cpp ** \~french - * \brief Implémentation des classes Threads et InfoThread + * \brief Implémentation des classes Threads et Process ** \~english - * \brief Implements classes Threads and InfoThread + * \brief Implements classes Threads and Process */ #include #include @@ -48,34 +48,36 @@ #include #include -#include "services/health/Threads.h" +#include "core/Process.h" -std::map Threads::threads; +std::map Process::threads; +long unsigned int Process::pid; +long Process::time; -void Threads::add() { - pthread_t i = pthread_self(); - Threads::add(i); -} +// void Process::add() { +// pthread_t i = pthread_self(); +// Process::add(i); +// } -void Threads::add(long unsigned int i) { +void Process::add(long unsigned int i) { BOOST_LOG_TRIVIAL(debug) << "add" << "(call thread " << i << ")"; threads.insert(std::make_pair(std::move(i), InfoThread(i))); } -void Threads::status(eThreadStatus value) { +void Process::status(eThreadStatus value) { pthread_t i = pthread_self(); - Threads::status(i, value); + Process::status(i, value); } -void Threads::status(long unsigned int i, eThreadStatus value) { - BOOST_LOG_TRIVIAL(debug) << "status : " << Threads::to_string(value) << "(call thread " << i << ")"; +void Process::status(long unsigned int i, eThreadStatus value) { + BOOST_LOG_TRIVIAL(debug) << "status : " << Process::to_string(value) << "(call thread " << i << ")"; std::map::iterator it; it = threads.find(i); if (it == threads.end()) { BOOST_LOG_TRIVIAL(debug) << "thread " << i << " not found !?"; return; } - it->second.set_status(Threads::to_string(value)); + it->second.set_status(Process::to_string(value)); BOOST_LOG_TRIVIAL(debug) << "status update : " << it->second.get_status(); if (value == eThreadStatus::PENDING) { @@ -106,9 +108,18 @@ void Threads::status(long unsigned int i, eThreadStatus value) { } +int Process::get_threads_count() { + return threads.size(); +} + +long unsigned int Process::get_pid() { return pid; } +void Process::set_pid(long unsigned int p) { pid = p; } +long Process::get_time() { return time; } +void Process::set_time(long processTime) { time = processTime; } + InfoThread::InfoThread(long unsigned int& i) { pid = i; - status = Threads::to_string(eThreadStatus::PENDING); + status = Process::to_string(eThreadStatus::PENDING); count = 0; duration = 0; time = 0; diff --git a/src/services/health/Threads.h b/src/core/Process.h similarity index 82% rename from src/services/health/Threads.h rename to src/core/Process.h index e839edb..110b79d 100644 --- a/src/services/health/Threads.h +++ b/src/core/Process.h @@ -36,11 +36,11 @@ */ /** - * \file services/health/Threads.h + * \file core/Process.h ** \~french - * \brief Définition des classes InfoThread et Threads + * \brief Définition des classes InfoThread et Process ** \~english - * \brief Define classes InfoThread and Threads + * \brief Define classes InfoThread and Process */ #pragma once @@ -50,7 +50,7 @@ #include -#include "Request.h" +#include "core/Request.h" enum eThreadStatus { UNKNOWN, @@ -190,7 +190,7 @@ class InfoThread { }; -class Threads { +class Process { private: /** * @brief Thread list information @@ -198,18 +198,51 @@ class Threads { */ static std::map threads; + /** + * @brief Process ID + * + */ + static long unsigned int pid; + + /** + * \~french \brief TimeStamp du process + * \~english \brief Process timestamp + */ + static long time; + /** * @brief Construct a new Stats object * */ - Threads(){}; + Process(){}; public: /** * @brief Destroy the Stats object * */ - ~Threads(){}; + ~Process(){}; + + /** + * @brief Get the process ID + * + * @return std::string + */ + static long unsigned int get_pid(); + + /** + * @brief Get the number of threads + * + * @return int + */ + static int get_threads_count(); + + /** + * @brief Set the process ID + * + * @return std::string + */ + static void set_pid(long unsigned int); /** * @brief Add a new thread to the map @@ -217,7 +250,7 @@ class Threads { * or else in main thread ! * */ - static void add(); + //static void add(); static void add(long unsigned int); /** @@ -257,5 +290,21 @@ class Threads { static std::string to_string (eThreadStatus st) { return std::string ( threadstatus_name[st] ); } + + /** + * \~french + * \brief Stocke la date du process principal + * \~english + * \brief Set the main process time + */ + static void set_time ( long process_time ); + + /** + * \~french + * \brief Obtient la date du process principal + * \~english + * \brief Get the main process time + */ + static long get_time(); }; diff --git a/src/Request.cpp b/src/core/Request.cpp similarity index 96% rename from src/Request.cpp rename to src/core/Request.cpp index 88dc249..ee1d048 100644 --- a/src/Request.cpp +++ b/src/core/Request.cpp @@ -43,7 +43,7 @@ * \brief Implement the Request Class analysing HTTP requests */ -#include "Request.h" +#include "core/Request.h" #include #include @@ -56,7 +56,7 @@ #include #include -#include "Utils.h" +#include "core/Utils.h" #include "config.h" Request::Request(FCGX_Request *fcgx) : fcgx_request(fcgx) { @@ -99,6 +99,12 @@ Request::Request(FCGX_Request *fcgx) : fcgx_request(fcgx) { std::transform(key.begin(), key.end(), key.begin(), ::tolower); query_params.insert(std::pair(key, it->second)); } + + // On stocke les paramètres de requête avec la clé en minuscule + char* tmp = FCGX_GetParam(SECRET_HEADER_NAME, fcgx->envp); + if (tmp != 0) { + secret = std::string(tmp); + } } Request::Request(std::string m, std::string u, std::map qp) : fcgx_request(NULL), method(m), query_params(qp), url(u) {} diff --git a/src/Request.h b/src/core/Request.h similarity index 98% rename from src/Request.h rename to src/core/Request.h index 7995c36..118dd8e 100644 --- a/src/Request.h +++ b/src/core/Request.h @@ -40,7 +40,7 @@ #include #include #include -#include "fcgiapp.h" +#include #include @@ -125,6 +125,12 @@ class Request { */ std::map query_params; + /** + * \~french \brief Secret + * \~english \brief Secret + */ + std::string secret; + /** * \~french \brief Liste des paramètres extraits du chemin de la requête * \~english \brief Parameters list from request path diff --git a/src/Rok4Server.cpp b/src/core/Rok4Server.cpp similarity index 90% rename from src/Rok4Server.cpp rename to src/core/Rok4Server.cpp index 15cebc7..6dbc4e7 100644 --- a/src/Rok4Server.cpp +++ b/src/core/Rok4Server.cpp @@ -65,11 +65,11 @@ #include #include -#include "Rok4Server.h" +#include "core/Rok4Server.h" +#include "core/Process.h" #include "config.h" #include "services/Router.h" -#include "services/health/Threads.h" void hangleSIGALARM(int id) { if (id == SIGALRM) { @@ -101,17 +101,17 @@ void* Rok4Server::thread_loop(void* arg) { } BOOST_LOG_TRIVIAL(debug) << "Thread " << pthread_self() << " traite une requete"; - Threads::status(eThreadStatus::RUNNING); + Process::status(eThreadStatus::RUNNING); Request* request = new Request(&fcgxRequest); - Router::process_request(request, server); + Router::process_request(request, server->get_services_configuration()); delete request; FCGX_Finish_r(&fcgxRequest); FCGX_Free(&fcgxRequest, 1); BOOST_LOG_TRIVIAL(debug) << "Thread " << pthread_self() << " en a fini avec la requete"; - Threads::status(eThreadStatus::AVAILABLE); + Process::status(eThreadStatus::AVAILABLE); } BOOST_LOG_TRIVIAL(debug) << "Extinction du thread"; @@ -151,7 +151,7 @@ void Rok4Server::run(sig_atomic_t signal_pending) { for (int i = 0; i < threads.size(); i++) { pthread_create(&(threads[i]), NULL, Rok4Server::thread_loop, (void*)this); - Threads::add(threads[i]); + Process::add(threads[i]); } if (signal_pending != 0) { @@ -175,15 +175,9 @@ void Rok4Server::terminate() { ServicesConfiguration* Rok4Server::get_services_configuration() { return services_configuration; } ServerConfiguration* Rok4Server::get_server_configuration() { return server_configuration; } -void Rok4Server::turn_off() {server_configuration->enabled = false; } -void Rok4Server::turn_on() {server_configuration->enabled = true; } std::vector& Rok4Server::get_threads() {return threads;} int Rok4Server::get_fcgi_socket() { return sock; } void Rok4Server::set_fcgi_socket(int sockFCGI) { sock = sockFCGI; } -int Rok4Server::get_pid() { return pid; } -void Rok4Server::set_pid(int processID) { pid = processID; } -long Rok4Server::get_time() { return time; } -void Rok4Server::set_time(long processTime) { time = processTime; } bool Rok4Server::is_running() { return running; } diff --git a/src/Rok4Server.h b/src/core/Rok4Server.h similarity index 84% rename from src/Rok4Server.h rename to src/core/Rok4Server.h index 8b4e765..5a5d9f4 100644 --- a/src/Rok4Server.h +++ b/src/core/Rok4Server.h @@ -48,7 +48,7 @@ class Server; #pragma once -#include "fcgiapp.h" +#include #include #include #include @@ -61,7 +61,7 @@ class Server; #include -#include "Request.h" +#include "core/Request.h" #include "config.h" @@ -97,18 +97,6 @@ class Rok4Server { */ int sock; - /** - * \~french \brief Identifiant du process - * \~english \brief Process identifier - */ - int pid; - - /** - * \~french \brief TimeStamp du process - * \~english \brief Process timestamp - */ - long time; - /** * \~french \brief Configurations des services * \~english \brief Services configuration @@ -145,18 +133,6 @@ class Rok4Server { */ ServerConfiguration* get_server_configuration() ; - /** - * \~french Active le serveur - * \~english Enable server - */ - void turn_on() ; - - /** - * \~french Désactive le serveur - * \~english Disable server - */ - void turn_off() ; - /** * \~french Retourne la liste des threads * \~english Return the threads list @@ -200,38 +176,6 @@ class Rok4Server { */ void set_fcgi_socket ( int socket_fcgi ) ; - /** - * \~french - * \brief Stocke le PId du process principal - * \~english - * \brief Set the main process PID - */ - void set_pid ( int process_id ); - - /** - * \~french - * \brief Obtient le PID du process principal - * \~english - * \brief Get the main process PID - */ - int get_pid(); - - /** - * \~french - * \brief Stocke la date du process principal - * \~english - * \brief Set the main process time - */ - void set_time ( long process_time ); - - /** - * \~french - * \brief Obtient la date du process principal - * \~english - * \brief Get the main process time - */ - long get_time(); - /** * \~french * \brief Demande l'arrêt du serveur diff --git a/src/core/Tile.h b/src/core/Tile.h new file mode 100644 index 0000000..1e778ec --- /dev/null +++ b/src/core/Tile.h @@ -0,0 +1,156 @@ +/* + * Copyright © (2011-2013) Institut national de l'information + * géographique et forestière + * + * Géoportail SAV + * + * This software is a computer program whose purpose is to publish geographic + * data using OGC WMS and WMTS protocol. + * + * This software is governed by the CeCILL-C license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL-C + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * + * knowledge of the CeCILL-C license and that you accept its terms. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "configurations/Layer.h" + +namespace Tile { + +/** + * \~french + * \brief Retourne la tuile demandée + * \return Flux de donnée + * \~english + * \brief Give the asked tile + * \return Data stream + */ +static DataStream* get_tile(ServicesConfiguration* services, Layer* layer, TileMatrixSet* tms, TileMatrix* tm, int column, int row, std::string format, Style* style) { + // Traitement de la requête + + if (tms->get_id() == layer->get_pyramid()->get_tms()->get_id()) { + // TMS d'interrogation natif + Level* level = layer->get_pyramid()->get_level(tm->get_id()); + + DataSource* d = level->get_tile(column, row); + if (d == NULL) { + return NULL; + } + + if (layer->is_raster() && layer->get_pyramid()->get_channels() == 1 && format == "image/png" && style->get_palette() && !style->get_palette()->is_empty()) { + return new DataStreamFromDataSource(new PaletteDataSource(d, style->get_palette())); + } else { + return new DataStreamFromDataSource(d); + } + } else { + // TMS d'interrogation à la demande, forcément du raster + + BoundingBox bbox = tm->tile_indices_to_bbox(column, row); + int height = tm->get_tile_height(); + int width = tm->get_tile_width(); + CRS* crs = tms->get_crs(); + bbox.crs = crs->get_request_code(); + + bool crs_equals = services->are_crs_equals(layer->get_pyramid()->get_tms()->get_crs()->get_proj_code(), crs->get_proj_code()); + + // On se donne maxium 3 tuiles sur 3 dans la pyramide source pour calculer cette tuile + Image* image = layer->get_pyramid()->getbbox(3, 3, bbox, width, height, crs, crs_equals, layer->get_resampling(), 0); + + if (image == NULL) { + BOOST_LOG_TRIVIAL(warning) << "Cannot process the tile in a non native TMS"; + return NULL; + } + + image->set_bbox(bbox); + image->set_crs(crs); + + if (format == "image/png" || format == "png") { + return new PNGEncoder(image, style->get_palette()); + } else if (format == "image/tiff" || format == "image/geotiff") { + bool is_geotiff = (format == "image/geotiff"); + + // Dans le cas d'un geotiff, on renseigne la valeur de nodata + // on ne peut mettre qu'une valeur, ce sera celle du premier canal + int nodata = *(layer->get_pyramid()->get_nodata_value()); + + // La donnée ne peut être retournée que dans le format de la pyramide source utilisée + + switch (layer->get_pyramid()->get_format()) { + case Rok4Format::TIFF_RAW_UINT8: + return new TiffRawEncoder(image, is_geotiff, nodata); + case Rok4Format::TIFF_LZW_UINT8: + return new TiffLZWEncoder(image, is_geotiff, nodata); + case Rok4Format::TIFF_ZIP_UINT8: + return new TiffDeflateEncoder(image, is_geotiff, nodata); + case Rok4Format::TIFF_PKB_UINT8: + return new TiffPackBitsEncoder(image, is_geotiff, nodata); + case Rok4Format::TIFF_RAW_FLOAT32: + return new TiffRawEncoder(image, is_geotiff, nodata); + case Rok4Format::TIFF_LZW_FLOAT32: + return new TiffLZWEncoder(image, is_geotiff, nodata); + case Rok4Format::TIFF_ZIP_FLOAT32: + return new TiffDeflateEncoder(image, is_geotiff, nodata); + case Rok4Format::TIFF_PKB_FLOAT32: + return new TiffPackBitsEncoder(image, is_geotiff, nodata); + default: + delete image; + return NULL; + } + } else if (format == "image/jpeg") { + switch (layer->get_pyramid()->get_format()) { + case Rok4Format::TIFF_JPG_UINT8: + return new JPEGEncoder(image, 75); + case Rok4Format::TIFF_JPG90_UINT8: + return new JPEGEncoder(image, 90); + default: + delete image; + return NULL; + } + + } else if (format == "image/x-bil;bits=32") { + return new BilEncoder(image); + } + } + + BOOST_LOG_TRIVIAL(error) << "On ne devrait pas passer par là"; + return NULL; +} +}; // namespace Tile diff --git a/src/Utils.h b/src/core/Utils.h similarity index 99% rename from src/Utils.h rename to src/core/Utils.h index fa975e8..b48f7f3 100644 --- a/src/Utils.h +++ b/src/core/Utils.h @@ -54,7 +54,7 @@ using boost::property_tree::xml_writer_settings; #include #include -#include "DataStreams.h" +#include "core/DataStreams.h" namespace Utils { /** diff --git a/src/main.cpp b/src/main.cpp index bbd4071..01788f3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -64,15 +64,13 @@ * \brief ROK4 Server executable */ -#include "Rok4Server.h" #include #include #include #include #include #include -#include "config.h" -#include "curl/curl.h" +#include #include #include #include @@ -89,6 +87,10 @@ namespace logging = boost::log; namespace keywords = boost::log::keywords; namespace sinks = boost::log::sinks; +#include "core/Rok4Server.h" +#include "core/Process.h" +#include "config.h" + Rok4Server* rok4server_instance; Rok4Server* rok4server_instance_tmp; bool reload; @@ -203,7 +205,7 @@ Rok4Server* load_configuration() { while (std::getline(list_content, layer_desc)) { Layer* layer = new Layer(layer_desc, services_configuration); if ( layer->is_ok() ) { - server_configuration->add_layer ( layer ); + services_configuration->add_layer ( layer ); } else { BOOST_LOG_TRIVIAL(error) << "Cannot load layer " << layer_desc << ": " << layer->get_error_message(); delete layer; @@ -211,7 +213,7 @@ Rok4Server* load_configuration() { } } - BOOST_LOG_TRIVIAL(info) << server_configuration->get_layers_count() << " layer(s) loaded" ; + BOOST_LOG_TRIVIAL(info) << services_configuration->get_layers_count() << " layer(s) loaded" ; // Instanciation du serveur return new Rok4Server ( server_configuration, services_configuration ); @@ -374,8 +376,8 @@ int main ( int argc, char** argv ) { auto start = std::chrono::system_clock::now(); std::time_t time = std::chrono::system_clock::to_time_t(start); - rok4server_instance->set_pid(pid); - rok4server_instance->set_time(time); + Process::set_pid(pid); + Process::set_time(time); // Remove Event Lock defer_signal--; @@ -404,11 +406,12 @@ int main ( int argc, char** argv ) { TmsBook::empty_trash(); StyleBook::empty_trash(); - CurlPool::clean_curls(); - ProjPool::clean_projs(); + CrsBook::clean_crss(); StoragePool::clean_storages(); IndexCache::clean_indexes(); - CrsBook::clean_crss(); + + CurlPool::clean_curls(); + ProjPool::clean_projs(); //CRYPTO clean - one time for the whole program EVP_cleanup(); diff --git a/src/services/Router.cpp b/src/services/Router.cpp index ff7f116..fdd7900 100644 --- a/src/services/Router.cpp +++ b/src/services/Router.cpp @@ -51,12 +51,11 @@ #include #include "services/Router.h" -#include "services/common/Service.h" #include "services/health/Service.h" #include "services/tms/Service.h" #include "services/wmts/Service.h" #include "services/admin/Service.h" -#include "services/tiles/Service.h" +#include "services/ogcapi/Service.h" #include "services/wms/Service.h" std::string get_message_from_http_status ( int http_status ) { @@ -260,35 +259,31 @@ int sendresponse ( DataStream* stream, Request* request ) { return 0; } -void Router::process_request(Request* req, Rok4Server* serv) { +void Router::process_request(Request* req, ServicesConfiguration* services) { - ServicesConfiguration* services = serv->get_services_configuration(); - bool enabled = serv->get_server_configuration()->is_enabled(); + bool enabled = services->is_enabled(); try { BOOST_LOG_TRIVIAL(info) << "Request: " << req->to_string(); if (services->get_health_service()->match_request(req)) { - sendresponse(services->get_health_service()->process_request(req, serv), req); + sendresponse(services->get_health_service()->process_request(req, services), req); } else if (services->get_admin_service()->match_request(req)) { - sendresponse(services->get_admin_service()->process_request(req, serv), req); - } - else if (enabled && services->get_common_service()->match_request(req)) { - sendresponse(services->get_common_service()->process_request(req, serv), req); + sendresponse(services->get_admin_service()->process_request(req, services), req); } else if (enabled && services->get_tms_service()->match_request(req)) { - sendresponse(services->get_tms_service()->process_request(req, serv), req); + sendresponse(services->get_tms_service()->process_request(req, services), req); } else if (enabled && services->get_wmts_service()->match_request(req)) { - sendresponse(services->get_wmts_service()->process_request(req, serv), req); + sendresponse(services->get_wmts_service()->process_request(req, services), req); } - else if (enabled && services->get_tiles_service()->match_request(req)) { - sendresponse(services->get_tiles_service()->process_request(req, serv), req); + else if (enabled && services->get_ogcapi_service()->match_request(req)) { + sendresponse(services->get_ogcapi_service()->process_request(req, services), req); } else if (enabled && services->get_wms_service()->match_request(req)) { - sendresponse(services->get_wms_service()->process_request(req, serv), req); + sendresponse(services->get_wms_service()->process_request(req, services), req); } else { throw new MessageDataStream("{\"error\": \"Bad Request\", \"error_description\": \"Unknown request path\"}", "application/json", 400); diff --git a/src/services/Router.h b/src/services/Router.h index 75505b0..79eb071 100644 --- a/src/services/Router.h +++ b/src/services/Router.h @@ -47,14 +47,14 @@ class Rok4Server; #pragma once -#include "fcgiapp.h" +#include #include #include -#include "Request.h" -#include "Rok4Server.h" -#include "DataStreams.h" +#include "core/Request.h" +#include "core/Rok4Server.h" +#include "core/DataStreams.h" /** * \author Institut national de l'information géographique et forestière @@ -72,7 +72,7 @@ class Router { * \~english * \brief Service and request type identification */ - static void process_request(Request* req, Rok4Server* serv); + static void process_request(Request* req, ServicesConfiguration* services); }; diff --git a/src/services/Service.cpp b/src/services/Service.cpp index d6c482f..7c5f66d 100644 --- a/src/services/Service.cpp +++ b/src/services/Service.cpp @@ -44,7 +44,7 @@ */ #include "services/Service.h" -#include "Request.h" +#include "core/Request.h" bool Service::match_route(std::string path, std::vector methods, Request* req) { @@ -66,7 +66,7 @@ bool Service::match_route(std::string path, std::vector methods, Re } }; -Service::Service (json11::Json& doc) { +Service::Service (json11::Json& doc, std::string default_title, std::string default_abstract, std::string default_endpoint_uri, std::string default_root_path) { if (doc.is_null()) { enabled = false; @@ -84,6 +84,62 @@ Service::Service (json11::Json& doc) { } else { enabled = false; } + + title = default_title; + abstract = default_abstract; + endpoint_uri = default_endpoint_uri; + root_path = default_root_path; + metadata = NULL; + + if (doc["title"].is_string()) { + title = doc["title"].string_value(); + } else if (! doc["title"].is_null()) { + error_message = "title have to be a string"; + return; + } + + if (doc["abstract"].is_string()) { + abstract = doc["abstract"].string_value(); + } else if (! doc["abstract"].is_null()) { + error_message = "abstract have to be a string"; + return; + } + + if (doc["keywords"].is_array()) { + for (json11::Json kw : doc["keywords"].array_items()) { + if (kw.is_string()) { + keywords.push_back(Keyword ( kw.string_value())); + } else { + error_message = "keywords have to be a string array"; + return; + } + } + } else if (! doc["keywords"].is_null()) { + error_message = "keywords have to be a string array"; + return; + } + + if (doc["endpoint_uri"].is_string()) { + endpoint_uri = doc["endpoint_uri"].string_value(); + } else if (! doc["endpoint_uri"].is_null()) { + error_message = "endpoint_uri have to be a string"; + return; + } + + if (doc["root_path"].is_string()) { + root_path = doc["root_path"].string_value(); + } else if (! doc["root_path"].is_null()) { + error_message = "root_path have to be a string"; + return; + } + + if (doc["metadata"].is_object()) { + metadata = new Metadata ( doc["metadata"] ); + if (metadata->get_missing_field() != "") { + error_message = "invalid metadata: have to own a field " + metadata->get_missing_field(); + return ; + } + } }; bool Service::match_request(Request* req) { diff --git a/src/services/Service.h b/src/services/Service.h index edaaaef..d11aa78 100644 --- a/src/services/Service.h +++ b/src/services/Service.h @@ -52,7 +52,9 @@ #include #include -class Rok4Server; +#include "configurations/Metadata.h" + +class ServicesConfiguration; class Request; /** @@ -69,6 +71,7 @@ class Service : public Configuration { std::vector keywords; std::string endpoint_uri; std::string root_path; + Metadata* metadata; bool enabled; /** @@ -100,13 +103,23 @@ class Service : public Configuration { * \~english * \brief Service constructor */ - Service (json11::Json& doc); + Service (json11::Json& doc, std::string default_title, std::string default_abstract, std::string default_endpoint_uri, std::string default_root_path); - virtual DataStream* process_request(Request* req, Rok4Server* serv) = 0; + virtual DataStream* process_request(Request* req, ServicesConfiguration* services) = 0; std::string get_endpoint_uri() {return endpoint_uri;}; bool is_enabled() {return enabled;}; bool match_request(Request* req); + + /** + * \~french + * \brief Destructeur + * \~english + * \brief Destructor + */ + ~Service() { + if (metadata) delete metadata; + }; }; diff --git a/src/services/admin/Exception.h b/src/services/admin/Exception.h index 35300d5..616882c 100644 --- a/src/services/admin/Exception.h +++ b/src/services/admin/Exception.h @@ -46,9 +46,9 @@ #pragma once #include -#include "boost/format.hpp" +#include -#include "DataStreams.h" +#include "core/DataStreams.h" /** * \author Institut national de l'information géographique et forestière diff --git a/src/services/admin/Service.cpp b/src/services/admin/Service.cpp index fd2b4fb..3cc3f0c 100644 --- a/src/services/admin/Service.cpp +++ b/src/services/admin/Service.cpp @@ -46,9 +46,9 @@ #include "services/admin/Service.h" #include "services/admin/Exception.h" -#include "Rok4Server.h" +#include "core/Rok4Server.h" -AdminService::AdminService (json11::Json& doc) : Service(doc) { +AdminService::AdminService (json11::Json& doc) : Service(doc, "ADMIN service", "ADMIN service", "http://localhost/admin", "/admin") { if (! is_ok()) { // Le constructeur du service générique a détecté une erreur, on ajoute simplement le service concerné dans le message @@ -61,34 +61,45 @@ AdminService::AdminService (json11::Json& doc) : Service(doc) { return; } - title = "ADMIN service"; - abstract = "ADMIN service"; + if (doc["secret"].is_string()) { + secret = doc["secret"].string_value(); + } else if (! doc["secret"].is_null()) { + error_message = "ADMIN service: secret have to be a string"; + return; + } else { + secret = ""; + } + keywords.push_back(Keyword ( "administration" )); - root_path = "/admin"; } -DataStream* AdminService::process_request(Request* req, Rok4Server* serv) { +DataStream* AdminService::process_request(Request* req, ServicesConfiguration* services) { BOOST_LOG_TRIVIAL(debug) << "ADMIN service"; + // Contrôle du secret + if (secret != "" && req->secret != secret) { + throw AdminException::get_error_message("Not authorized request", "Operation forbidden", 403); + } + if ( match_route( "/layers/([^/]+)", {"POST"}, req ) ) { BOOST_LOG_TRIVIAL(debug) << "ADDLAYER request"; - return add_layer(req, serv); + return add_layer(req, services); } else if ( match_route( "/layers/([^/]+)", {"PUT"}, req ) ) { BOOST_LOG_TRIVIAL(debug) << "UPDATELAYER request"; - return update_layer(req, serv); + return update_layer(req, services); } else if ( match_route( "/layers/([^/]+)", {"DELETE"}, req ) ) { BOOST_LOG_TRIVIAL(debug) << "DELETELAYER request"; - return delete_layer(req, serv); + return delete_layer(req, services); } else if ( match_route( "/on", {"PUT"}, req ) ) { BOOST_LOG_TRIVIAL(debug) << "TURNON request"; - return turn_on(req, serv); + return turn_on(req, services); } else if ( match_route( "/off", {"PUT"}, req ) ) { BOOST_LOG_TRIVIAL(debug) << "TURNOFF request"; - return turn_off(req, serv); + return turn_off(req, services); } else { throw AdminException::get_error_message("Unknown admin request path", "Operation not supported", 400); } diff --git a/src/services/admin/Service.h b/src/services/admin/Service.h index 0470265..2a90c57 100644 --- a/src/services/admin/Service.h +++ b/src/services/admin/Service.h @@ -58,14 +58,16 @@ class AdminService : public Service { private: - DataStream* turn_on ( Request* req, Rok4Server* serv ); - DataStream* turn_off ( Request* req, Rok4Server* serv ); - DataStream* add_layer ( Request* req, Rok4Server* serv ); - DataStream* update_layer ( Request* req, Rok4Server* serv ); - DataStream* delete_layer ( Request* req, Rok4Server* serv ); + DataStream* turn_on ( Request* req, ServicesConfiguration* services ); + DataStream* turn_off ( Request* req, ServicesConfiguration* services ); + DataStream* add_layer ( Request* req, ServicesConfiguration* services ); + DataStream* update_layer ( Request* req, ServicesConfiguration* services ); + DataStream* delete_layer ( Request* req, ServicesConfiguration* services ); + + std::string secret; public: - DataStream* process_request(Request* req, Rok4Server* serv); + DataStream* process_request(Request* req, ServicesConfiguration* services); /** * \~french diff --git a/src/services/admin/layers.cpp b/src/services/admin/layers.cpp index 6799ff8..e5f5d16 100644 --- a/src/services/admin/layers.cpp +++ b/src/services/admin/layers.cpp @@ -46,70 +46,70 @@ #include "services/admin/Service.h" #include "services/admin/Exception.h" -#include "Rok4Server.h" +#include "core/Rok4Server.h" -DataStream* AdminService::add_layer ( Request* req, Rok4Server* serv ) { +DataStream* AdminService::add_layer ( Request* req, ServicesConfiguration* services ) { std::string str_layer = req->path_params.at(0); - Layer* layer = serv->get_server_configuration()->get_layer(str_layer); + Layer* layer = services->get_layer(str_layer); if ( layer != NULL ) throw AdminException::get_error_message("Layer already exists.", "Configuration conflict", 409); - layer = new Layer( str_layer, req->body, serv->get_services_configuration() ); + layer = new Layer( str_layer, req->body, services ); if ( ! layer->is_ok() ) { std::string msg = layer->get_error_message(); delete layer; throw AdminException::get_error_message(msg, "Configuration issue", 400); } - serv->get_server_configuration()->add_layer ( layer ); - serv->get_services_configuration()->clean_cache(); + services->add_layer ( layer ); + services->clean_cache(); return new EmptyResponseDataStream (); } -DataStream* AdminService::update_layer ( Request* req, Rok4Server* serv ) { +DataStream* AdminService::update_layer ( Request* req, ServicesConfiguration* services ) { std::string str_layer = req->path_params.at(0); if ( contain_chars(str_layer, "\"")) { - BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in TILES layer: " << str_layer ; + BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in layer: " << str_layer ; throw AdminException::get_error_message("Layer does not exists.", "Not found", 404); } - Layer* layer = serv->get_server_configuration()->get_layer(str_layer); + Layer* layer = services->get_layer(str_layer); if ( layer == NULL ) throw AdminException::get_error_message("Layer " + str_layer + " does not exists.", "Not found", 404); - Layer* new_layer = new Layer( str_layer, req->body, serv->get_services_configuration() ); + Layer* new_layer = new Layer( str_layer, req->body, services ); if ( ! new_layer->is_ok() ) { std::string msg = new_layer->get_error_message(); delete new_layer; throw AdminException::get_error_message(msg, "Configuration issue", 400); } - serv->get_server_configuration()->delete_layer ( layer->get_id() ); - serv->get_server_configuration()->add_layer ( new_layer ); - serv->get_services_configuration()->clean_cache(); + services->delete_layer ( layer->get_id() ); + services->add_layer ( new_layer ); + services->clean_cache(); return new EmptyResponseDataStream (); } -DataStream* AdminService::delete_layer ( Request* req, Rok4Server* serv ) { +DataStream* AdminService::delete_layer ( Request* req, ServicesConfiguration* services ) { std::string str_layer = req->path_params.at(0); if ( contain_chars(str_layer, "\"")) { - BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in TILES layer: " << str_layer ; + BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in layer: " << str_layer ; throw AdminException::get_error_message("Layer does not exists.", "Not found", 404); } - Layer* layer = serv->get_server_configuration()->get_layer(str_layer); + Layer* layer = services->get_layer(str_layer); if ( layer == NULL ) throw AdminException::get_error_message("Layer " + str_layer + " does not exists.", "Not found", 404); - serv->get_server_configuration()->delete_layer ( layer->get_id() ); - serv->get_services_configuration()->clean_cache(); + services->delete_layer ( layer->get_id() ); + services->clean_cache(); return new EmptyResponseDataStream (); } \ No newline at end of file diff --git a/src/services/admin/turnonoff.cpp b/src/services/admin/turnonoff.cpp index 05941b3..d38e017 100644 --- a/src/services/admin/turnonoff.cpp +++ b/src/services/admin/turnonoff.cpp @@ -46,18 +46,18 @@ #include "services/admin/Service.h" #include "services/admin/Exception.h" -#include "Rok4Server.h" +#include "core/Rok4Server.h" -DataStream* AdminService::turn_on ( Request* req, Rok4Server* serv ) { +DataStream* AdminService::turn_on ( Request* req, ServicesConfiguration* services ) { - serv->turn_on(); + services->enabled = true; return new EmptyResponseDataStream(); } -DataStream* AdminService::turn_off ( Request* req, Rok4Server* serv ) { +DataStream* AdminService::turn_off ( Request* req, ServicesConfiguration* services ) { - serv->turn_off(); + services->enabled = false; return new EmptyResponseDataStream(); } \ No newline at end of file diff --git a/src/services/common/Exception.h b/src/services/common/Exception.h deleted file mode 100644 index c76dce3..0000000 --- a/src/services/common/Exception.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright © (2011-2013) Institut national de l'information - * géographique et forestière - * - * Géoportail SAV - * - * This software is a computer program whose purpose is to publish geographic - * data using OGC WMS and WMTS protocol. - * - * This software is governed by the CeCILL-C license under French law and - * abiding by the rules of distribution of free software. You can use, - * modify and/ or redistribute the software under the terms of the CeCILL-C - * license as circulated by CEA, CNRS and INRIA at the following URL - * "http://www.cecill.info". - * - * As a counterpart to the access to the source code and rights to copy, - * modify and redistribute granted by the license, users are provided only - * with a limited warranty and the software's author, the holder of the - * economic rights, and the successive licensors have only limited - * liability. - * - * In this respect, the user's attention is drawn to the risks associated - * with loading, using, modifying and/or developing or reproducing the - * software by the user in light of its specific status of free software, - * that may mean that it is complicated to manipulate, and that also - * therefore means that it is reserved for developers and experienced - * professionals having in-depth computer knowledge. Users are therefore - * encouraged to load and test the software's suitability as regards their - * requirements in conditions enabling the security of their systems and/or - * data to be ensured and, more generally, to use and operate it in the - * same conditions as regards security. - * - * The fact that you are presently reading this means that you have had - * - * knowledge of the CeCILL-C license and that you accept its terms. - */ - -/** - * \file services/common/Exception.h - ** \~french - * \brief Définition de la classe CommonException - ** \~english - * \brief Define classe CommonException - */ - -#pragma once - -#include -#include "boost/format.hpp" - -#include "DataStreams.h" - -/** - * \author Institut national de l'information géographique et forestière - * \~french - * \brief Gestion des erreurs du service global - * \details Cette classe est prévue pour être utilisée sans instance. Les erreurs ont le formalisme suivant : - * \code{.xml} - * - * - * An error occured - * - * \endcode - */ -class CommonException { -private: - static std::string json_template; - -public: - static MessageDataStream* get_error_message(std::string type, std::string title, int status); -}; - diff --git a/src/services/common/Service.cpp b/src/services/common/Service.cpp deleted file mode 100644 index 396d6d1..0000000 --- a/src/services/common/Service.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright © (2011-2013) Institut national de l'information - * géographique et forestière - * - * Géoportail SAV - * - * This software is a computer program whose purpose is to publish geographic - * data using OGC WMS and WMTS protocol. - * - * This software is governed by the CeCILL-C license under French law and - * abiding by the rules of distribution of free software. You can use, - * modify and/ or redistribute the software under the terms of the CeCILL-C - * license as circulated by CEA, CNRS and INRIA at the following URL - * "http://www.cecill.info". - * - * As a counterpart to the access to the source code and rights to copy, - * modify and redistribute granted by the license, users are provided only - * with a limited warranty and the software's author, the holder of the - * economic rights, and the successive licensors have only limited - * liability. - * - * In this respect, the user's attention is drawn to the risks associated - * with loading, using, modifying and/or developing or reproducing the - * software by the user in light of its specific status of free software, - * that may mean that it is complicated to manipulate, and that also - * therefore means that it is reserved for developers and experienced - * professionals having in-depth computer knowledge. Users are therefore - * encouraged to load and test the software's suitability as regards their - * requirements in conditions enabling the security of their systems and/or - * data to be ensured and, more generally, to use and operate it in the - * same conditions as regards security. - * - * The fact that you are presently reading this means that you have had - * - * knowledge of the CeCILL-C license and that you accept its terms. - */ - -/** - * \file services/common/Service.cpp - ** \~french - * \brief Implémentation de la classe CommonService - ** \~english - * \brief Implements classe CommonService - */ - -#include - -#include "services/common/Service.h" -#include "services/common/Exception.h" - -#include "Rok4Server.h" - -CommonService::CommonService (json11::Json& doc) : Service(doc) { - - if (! is_ok()) { - // Le constructeur du service générique a détecté une erreur, on ajoute simplement le service concerné dans le message - error_message = "COMMON service: " + error_message; - return; - } - - if (doc.is_null()) { - // Le service a déjà été mis comme n'étant pas actif - return; - } - - if (doc["title"].is_string()) { - title = doc["title"].string_value(); - } else if (! doc["title"].is_null()) { - error_message = "COMMON service: title have to be a string"; - return; - } else { - title = "COMMON service"; - } - - if (doc["abstract"].is_string()) { - abstract = doc["abstract"].string_value(); - } else if (! doc["abstract"].is_null()) { - error_message = "COMMON service: abstract have to be a string"; - return; - } else { - abstract = "COMMON service"; - } - - if (doc["keywords"].is_array()) { - for (json11::Json kw : doc["keywords"].array_items()) { - if (kw.is_string()) { - keywords.push_back(Keyword ( kw.string_value())); - } else { - error_message = "COMMON service: keywords have to be a string array"; - return; - } - } - } else if (! doc["keywords"].is_null()) { - error_message = "COMMON service: keywords have to be a string array"; - return; - } - - if (doc["endpoint_uri"].is_string()) { - endpoint_uri = doc["endpoint_uri"].string_value(); - } else if (! doc["endpoint_uri"].is_null()) { - error_message = "COMMON service: endpoint_uri have to be a string"; - return; - } else { - endpoint_uri = "http://localhost/common"; - } - - if (doc["root_path"].is_string()) { - root_path = doc["root_path"].string_value(); - } else if (! doc["root_path"].is_null()) { - error_message = "COMMON service: root_path have to be a string"; - return; - } else { - root_path = "/common"; - } -} - -DataStream* CommonService::process_request(Request* req, Rok4Server* serv) { - BOOST_LOG_TRIVIAL(debug) << "COMMON service"; - - if ( match_route( "", {"GET"}, req ) ) { - BOOST_LOG_TRIVIAL(debug) << "GETLANDINGPAGE request"; - return get_landing_page(req, serv); - } else { - throw CommonException::get_error_message("ResourceNotFound", "Unknown common request path", 404); - } -}; \ No newline at end of file diff --git a/src/services/common/Service.h b/src/services/common/Service.h deleted file mode 100644 index c434ff7..0000000 --- a/src/services/common/Service.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright © (2011-2013) Institut national de l'information - * géographique et forestière - * - * Géoportail SAV - * - * This software is a computer program whose purpose is to publish geographic - * data using OGC WMS and WMTS protocol. - * - * This software is governed by the CeCILL-C license under French law and - * abiding by the rules of distribution of free software. You can use, - * modify and/ or redistribute the software under the terms of the CeCILL-C - * license as circulated by CEA, CNRS and INRIA at the following URL - * "http://www.cecill.info". - * - * As a counterpart to the access to the source code and rights to copy, - * modify and redistribute granted by the license, users are provided only - * with a limited warranty and the software's author, the holder of the - * economic rights, and the successive licensors have only limited - * liability. - * - * In this respect, the user's attention is drawn to the risks associated - * with loading, using, modifying and/or developing or reproducing the - * software by the user in light of its specific status of free software, - * that may mean that it is complicated to manipulate, and that also - * therefore means that it is reserved for developers and experienced - * professionals having in-depth computer knowledge. Users are therefore - * encouraged to load and test the software's suitability as regards their - * requirements in conditions enabling the security of their systems and/or - * data to be ensured and, more generally, to use and operate it in the - * same conditions as regards security. - * - * The fact that you are presently reading this means that you have had - * - * knowledge of the CeCILL-C license and that you accept its terms. - */ - -/** - * \file services/common/Service.h - ** \~french - * \brief Définition de la classe CommonService - ** \~english - * \brief Define classe CommonService - */ - -class CommonService; - -#pragma once - -#include "services/Service.h" - -/** - * \author Institut national de l'information géographique et forestière - * \~french - * \brief Gestion du service global du serveur - */ -class CommonService : public Service { - -private: - DataStream* get_landing_page (Request* req, Rok4Server* serv); - - std::string cache_getlandingpage; - -public: - DataStream* process_request(Request* req, Rok4Server* serv); - - /** - * \~french - * \brief Supprime les réponses cachées - * \~english - * \brief Remove cached responses - */ - void clean_cache() { - cache_mtx.lock(); - cache_getlandingpage.clear(); - cache_mtx.unlock(); - }; - - - /** - * \~french - * \brief Constructeur du service 'common' - * \~english - * \brief Service constructor - */ - CommonService (json11::Json& doc); - -}; - diff --git a/src/services/common/getcapabilities.cpp b/src/services/common/getcapabilities.cpp deleted file mode 100644 index 2c9691a..0000000 --- a/src/services/common/getcapabilities.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright © (2011-2013) Institut national de l'information - * géographique et forestière - * - * Géoportail SAV - * - * This software is a computer program whose purpose is to publish geographic - * data using OGC WMS and WMTS protocol. - * - * This software is governed by the CeCILL-C license under French law and - * abiding by the rules of distribution of free software. You can use, - * modify and/ or redistribute the software under the terms of the CeCILL-C - * license as circulated by CEA, CNRS and INRIA at the following URL - * "http://www.cecill.info". - * - * As a counterpart to the access to the source code and rights to copy, - * modify and redistribute granted by the license, users are provided only - * with a limited warranty and the software's author, the holder of the - * economic rights, and the successive licensors have only limited - * liability. - * - * In this respect, the user's attention is drawn to the risks associated - * with loading, using, modifying and/or developing or reproducing the - * software by the user in light of its specific status of free software, - * that may mean that it is complicated to manipulate, and that also - * therefore means that it is reserved for developers and experienced - * professionals having in-depth computer knowledge. Users are therefore - * encouraged to load and test the software's suitability as regards their - * requirements in conditions enabling the security of their systems and/or - * data to be ensured and, more generally, to use and operate it in the - * same conditions as regards security. - * - * The fact that you are presently reading this means that you have had - * - * knowledge of the CeCILL-C license and that you accept its terms. - */ - -/** - * \file services/common/getcapabilities.cpp - ** \~french - * \brief Implémentation de la classe CommonService - ** \~english - * \brief Implements classe CommonService - */ - -#include - -#include "services/common/Exception.h" -#include "services/common/Service.h" -#include "Rok4Server.h" - -DataStream* CommonService::get_landing_page ( Request* req, Rok4Server* serv ) { - - std::string f = req->get_query_param("f"); - if (f != "" && f != "application/json" && f != "json") { - throw CommonException::get_error_message("InvalidParameter", "Format unknown", 400); - } - - ServicesConfiguration* services = serv->get_services_configuration(); - - if ( ! cache_getlandingpage.empty()) { - return new MessageDataStream ( cache_getlandingpage, "application/json", 200 ); - } - - std::vector links; - - links.push_back(json11::Json::object { - { "href", endpoint_uri}, - { "rel", "self"}, - { "type", "application/json"}, - { "title", "this document"} - }); - - if (services->get_wms_service()->is_enabled()) { - links.push_back(json11::Json::object { - { "href", services->get_wms_service()->get_endpoint_uri() + "?SERVICE=WMS&REQUEST=GetCapabilities&VERSION=1.3.0"}, - { "rel", "data"}, - { "type", "application/xml"}, - { "title", "OGC Web Map Service capabilities"} - }); - } - - if (services->get_wmts_service()->is_enabled()) { - links.push_back(json11::Json::object { - { "href", services->get_wmts_service()->get_endpoint_uri() + "?SERVICE=WMTS&REQUEST=GetCapabilities&VERSION=1.0.0"}, - { "rel", "data"}, - { "type", "application/xml"}, - { "title", "OGC Web Map Tile Service capabilities"} - }); - } - - if (services->get_tms_service()->is_enabled()) { - links.push_back(json11::Json::object { - { "href", services->get_tms_service()->get_endpoint_uri() + "/1.0.0"}, - { "rel", "data"}, - { "type", "application/xml"}, - { "title", "Tile Map Service capabilities"} - }); - } - - if (services->get_tiles_service()->is_enabled()) { - links.push_back(json11::Json::object { - { "href", services->get_tiles_service()->get_endpoint_uri() + "/collections?f=json"}, - { "rel", "data"}, - { "type", "application/json"}, - { "title", "OGC API Tiles capabilities"} - }); - } - - json11::Json::object res = json11::Json::object { - { "title", title }, - { "description", abstract }, - { "links", links } - }; - - cache_mtx.lock(); - cache_getlandingpage = json11::Json{ res }.dump(); - cache_mtx.unlock(); - return new MessageDataStream ( cache_getlandingpage, "application/json", 200 ); -} \ No newline at end of file diff --git a/src/services/health/Exception.h b/src/services/health/Exception.h index f34be0f..746b773 100644 --- a/src/services/health/Exception.h +++ b/src/services/health/Exception.h @@ -46,9 +46,9 @@ #pragma once #include -#include "boost/format.hpp" +#include -#include "DataStreams.h" +#include "core/DataStreams.h" /** * \author Institut national de l'information géographique et forestière diff --git a/src/services/health/Service.cpp b/src/services/health/Service.cpp index a6feacc..a83316f 100644 --- a/src/services/health/Service.cpp +++ b/src/services/health/Service.cpp @@ -46,12 +46,12 @@ #include #include "services/health/Service.h" -#include "services/health/Threads.h" #include "services/health/Exception.h" -#include "Rok4Server.h" +#include "core/Rok4Server.h" +#include "core/Process.h" -HealthService::HealthService (json11::Json& doc) : Service(doc) { +HealthService::HealthService (json11::Json& doc) : Service(doc, "HEALTH service", "HEALTH service", "http://localhost/healthcheck", "/healthcheck") { if (! is_ok()) { // Le constructeur du service générique a détecté une erreur, on ajoute simplement le service concerné dans le message @@ -64,31 +64,28 @@ HealthService::HealthService (json11::Json& doc) : Service(doc) { return; } - title = "HEALTH service"; - abstract = "HEALTH service"; keywords.push_back(Keyword ( "health" )); keywords.push_back(Keyword ( "check" )); - root_path = "/healthcheck"; } -DataStream* HealthService::process_request(Request* req, Rok4Server* serv) { +DataStream* HealthService::process_request(Request* req, ServicesConfiguration* services) { BOOST_LOG_TRIVIAL(debug) << "HEALTH service"; if ( match_route( "", {"GET"}, req ) ) { BOOST_LOG_TRIVIAL(debug) << "GETHEALTH request"; - return get_health(req, serv); + return get_health(req, services); } else if ( match_route( "/info", {"GET"}, req ) ) { BOOST_LOG_TRIVIAL(debug) << "GETINFOS request"; - return get_infos(req, serv); + return get_infos(req, services); } else if ( match_route( "/threads", {"GET"}, req ) ) { BOOST_LOG_TRIVIAL(debug) << "GETTHREADS request"; - return get_threads(req, serv); + return get_threads(req, services); } else if ( match_route( "/depends", {"GET"}, req ) ) { BOOST_LOG_TRIVIAL(debug) << "GETDEPENDENCIES request"; - return get_dependencies(req, serv); + return get_dependencies(req, services); } else { throw HealthException::get_error_message("Unknown health request path", 400); } diff --git a/src/services/health/Service.h b/src/services/health/Service.h index d009a9a..91e0399 100644 --- a/src/services/health/Service.h +++ b/src/services/health/Service.h @@ -58,13 +58,13 @@ class HealthService : public Service { private: - DataStream* get_dependencies ( Request* req, Rok4Server* serv ); - DataStream* get_threads ( Request* req, Rok4Server* serv ); - DataStream* get_infos ( Request* req, Rok4Server* serv ); - DataStream* get_health ( Request* req, Rok4Server* serv ); + DataStream* get_dependencies ( Request* req, ServicesConfiguration* services ); + DataStream* get_threads ( Request* req, ServicesConfiguration* services ); + DataStream* get_infos ( Request* req, ServicesConfiguration* services ); + DataStream* get_health ( Request* req, ServicesConfiguration* services ); public: - DataStream* process_request(Request* req, Rok4Server* serv); + DataStream* process_request(Request* req, ServicesConfiguration* services ); /** * \~french diff --git a/src/services/health/gets.cpp b/src/services/health/gets.cpp index ff4ca05..db4f6b2 100644 --- a/src/services/health/gets.cpp +++ b/src/services/health/gets.cpp @@ -48,27 +48,27 @@ #include #include "services/health/Service.h" -#include "services/health/Threads.h" #include "services/health/Exception.h" -#include "Rok4Server.h" +#include "core/Rok4Server.h" +#include "core/Process.h" -DataStream* HealthService::get_health ( Request* req, Rok4Server* serv ) { +DataStream* HealthService::get_health ( Request* req, ServicesConfiguration* services ) { json11::Json res = json11::Json::object { { "version", VERSION }, - { "pid", serv->get_pid() }, - { "time", (int) serv->get_time() }, - { "status", serv->get_server_configuration()->is_enabled() ? "OK" : "DISABLED" } + { "pid", (int) Process::get_pid() }, + { "time", (int) Process::get_time() }, + { "status", services->enabled ? "OK" : "DISABLED" } }; return new MessageDataStream ( res.dump(), "application/json", 200 ); } -DataStream* HealthService::get_infos ( Request* req, Rok4Server* serv ) { +DataStream* HealthService::get_infos ( Request* req, ServicesConfiguration* services ) { std::vector layers; - for(auto const& l: serv->get_server_configuration()->get_layers()) { + for(auto const& l: services->get_layers()) { layers.push_back(l.first); } @@ -91,17 +91,17 @@ DataStream* HealthService::get_infos ( Request* req, Rok4Server* serv ) { return new MessageDataStream ( res.dump(), "application/json", 200 ); } -DataStream* HealthService::get_threads ( Request* req, Rok4Server* serv ) { +DataStream* HealthService::get_threads ( Request* req, ServicesConfiguration* services ) { json11::Json res = json11::Json::object { - { "number", (int) serv->get_threads().size() }, - { "threads", Threads::to_json() } + { "number", Process::get_threads_count() }, + { "threads", Process::to_json() } }; return new MessageDataStream ( res.dump(), "application/json", 200 ); } -DataStream* HealthService::get_dependencies ( Request* req, Rok4Server* serv ) { +DataStream* HealthService::get_dependencies ( Request* req, ServicesConfiguration* services ) { int file_count, s3_count, ceph_count, swift_count; StoragePool::get_storages_count(file_count, s3_count, ceph_count, swift_count); diff --git a/src/services/common/Exception.cpp b/src/services/ogcapi/Exception.cpp similarity index 86% rename from src/services/common/Exception.cpp rename to src/services/ogcapi/Exception.cpp index db35456..4c84f2d 100644 --- a/src/services/common/Exception.cpp +++ b/src/services/ogcapi/Exception.cpp @@ -36,17 +36,17 @@ */ /** - * \file services/common/Exception.cpp + * \file services/ogcapi/Exception.cpp ** \~french - * \brief Implémentation de la classe CommonException + * \brief Implémentation de la classe OgcApiException ** \~english - * \brief Implements classe CommonException + * \brief Implements classe OgcApiException */ -#include "services/common/Exception.h" +#include "services/ogcapi/Exception.h" -std::string CommonException::json_template = "{ \"type\": \"%s\", \"title\": \"%s\", \"status\": %s }"; +std::string OgcApiException::json_template = "{ \"type\": \"%s\", \"title\": \"%s\", \"status\": %s }"; -MessageDataStream* CommonException::get_error_message(std::string type, std::string title, int status) { +MessageDataStream* OgcApiException::get_error_message(std::string type, std::string title, int status) { return new MessageDataStream(str(boost::format(json_template) % type % title % status), "application/json", status); } \ No newline at end of file diff --git a/src/services/tiles/Exception.h b/src/services/ogcapi/Exception.h similarity index 89% rename from src/services/tiles/Exception.h rename to src/services/ogcapi/Exception.h index 6b0f87e..af443e0 100644 --- a/src/services/tiles/Exception.h +++ b/src/services/ogcapi/Exception.h @@ -36,24 +36,24 @@ */ /** - * \file services/tiles/Exception.h + * \file services/ogcapi/Exception.h ** \~french - * \brief Définition de la classe TilesException + * \brief Définition de la classe OgcApiException ** \~english - * \brief Define classe TilesException + * \brief Define classe OgcApiException */ #pragma once #include -#include "boost/format.hpp" +#include -#include "DataStreams.h" +#include "core/DataStreams.h" /** * \author Institut national de l'information géographique et forestière * \~french - * \brief Gestion des erreurs du service OGC API Tiles + * \brief Gestion des erreurs du service OGC API * \details Cette classe est prévue pour être utilisée sans instance. Les erreurs ont le formalisme suivant : * \code{.json} * { @@ -62,7 +62,7 @@ * } * \endcode */ -class TilesException { +class OgcApiException { private: static std::string json_template; diff --git a/src/services/ogcapi/Service.cpp b/src/services/ogcapi/Service.cpp new file mode 100644 index 0000000..096e6d4 --- /dev/null +++ b/src/services/ogcapi/Service.cpp @@ -0,0 +1,179 @@ +/* + * Copyright © (2011-2013) Institut national de l'information + * géographique et forestière + * + * Géoportail SAV + * + * This software is a computer program whose purpose is to publish geographic + * data using OGC WMS and WMTS protocol. + * + * This software is governed by the CeCILL-C license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL-C + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * + * knowledge of the CeCILL-C license and that you accept its terms. + */ + +/** + * \file services/ogcapi/Service.cpp + ** \~french + * \brief Implémentation de la classe OgcApiService + ** \~english + * \brief Implements classe OgcApiService + */ + +#include "services/ogcapi/Service.h" + +#include + +#include "core/Rok4Server.h" +#include "services/ogcapi/Exception.h" + +std::map OgcApiService::ogcapi_format_to_mime_type = { + {"png", "image/png"}, + {"jpg", "image/jpeg"}, + {"mvt", "application/x-protobuf"}, + {"tiff", "image/geotiff"}, + {"bil", "image/x-bil;bits=32"}, + {"asc", "text/asc"}}; + +OgcApiService::OgcApiService(json11::Json& doc) : Service(doc, "OGC API service", "OGC API service", "http://localhost/ogcapi", "/ogcapi") { + if (!is_ok()) { + // Le constructeur du service générique a détecté une erreur, on ajoute simplement le service concerné dans le message + error_message = "OGCAPI service: " + error_message; + return; + } + + if (doc.is_null()) { + // Le service a déjà été mis comme n'étant pas actif + return; + } + + if (doc["tiles"].is_bool()) { + tiles = doc["tiles"].bool_value(); + } else if (!doc["tiles"].is_null()) { + error_message = "OGC API service: tiles have to be a boolean"; + return; + } else { + tiles = true; + } + + if (doc["maps"].is_bool()) { + maps = doc["maps"].bool_value(); + } else if (!doc["maps"].is_null()) { + error_message = "OGC API service: maps have to be a boolean"; + return; + } else { + maps = true; + } + + if (doc["default_size"].is_number() && doc["default_size"].number_value() >= 64 && doc["default_size"].number_value() <= 4096) { + default_size = doc["default_size"].number_value(); + } else if (! doc["default_size"].is_null()) { + error_message = "OGC API service: default_size have to be an integer between 64 and 4096"; + return; + } else { + default_size = 256; + } +} + +DataStream* OgcApiService::process_request(Request* req, ServicesConfiguration* services) { + BOOST_LOG_TRIVIAL(debug) << "OGC API service"; + + if (match_route("", {"GET"}, req)) { + BOOST_LOG_TRIVIAL(debug) << "GET LANDING PAGE request"; + return get_landing_page(req, services); + } else if (match_route("/conformance", {"GET"}, req)) { + BOOST_LOG_TRIVIAL(debug) << "GET CONFORMANCE request"; + return get_conformance(req, services); + } + // API + else if (match_route("/api/all-collections", {"GET"}, req)) { + BOOST_LOG_TRIVIAL(debug) << "GET API COLLECTION request"; + return get_api_collections(req, services); + } else if (match_route("/api/vectorTiles-collections", {"GET"}, req)) { + BOOST_LOG_TRIVIAL(debug) << "GET API VECTOR COLLECTIONS request"; + return get_api_vector_collections(req, services); + } else if (match_route("/api/tileMatrixSets", {"GET"}, req)) { + BOOST_LOG_TRIVIAL(debug) << "GET API TILE MATRIX SETS request"; + return get_api_tilematrixsets(req, services); + } else if (match_route("/api/styles", {"GET"}, req)) { + BOOST_LOG_TRIVIAL(debug) << "GET API STYLES request"; + return get_api_styles(req, services); + } + // TMS + else if (match_route("/tileMatrixSets", {"GET"}, req)) { + BOOST_LOG_TRIVIAL(debug) << "GET TILE MATRIX SETS request"; + return get_tilematrixsets(req, services); + } else if (match_route("/tileMatrixSets/([^/]+)", {"GET"}, req)) { + BOOST_LOG_TRIVIAL(debug) << "GET TILE MATRIX SET request"; + return get_tilematrixset(req, services); + } + // Collections + else if (match_route("/collections", {"GET"}, req)) { + BOOST_LOG_TRIVIAL(debug) << "GET COLLECTIONS request"; + return get_collections(req, services); + } else if (match_route("/collections/([^/]+)", {"GET"}, req)) { + BOOST_LOG_TRIVIAL(debug) << "GET COLLECTION request"; + return get_collection(req, services); + } + + // TILES + // Données vecteur + else if (tiles && match_route("/collections/([^/]+)/tiles", {"GET"}, req)) { + BOOST_LOG_TRIVIAL(debug) << "GET TILESETS vector request"; + return get_tilesets(req, services, false); + } else if (tiles && match_route("/collections/([^/]+)/tiles/([^/]+)", {"GET"}, req)) { + BOOST_LOG_TRIVIAL(debug) << "GET TILESET vector request"; + return get_tileset(req, services, false); + } else if (tiles && match_route("/collections/([^/]+)/tiles/([^/]+)/([^/]+)/([^/]+)/([^/]+)", {"GET"}, req)) { + BOOST_LOG_TRIVIAL(debug) << "GET TILE vector request"; + return get_tile(req, services, false); + } + // Données raster + else if (tiles && match_route("/collections/([^/]+)/map/tiles", {"GET"}, req)) { + BOOST_LOG_TRIVIAL(debug) << "GET TILE SETS map request"; + return get_tilesets(req, services, true); + } else if (tiles && match_route("/collections/([^/]+)/map/tiles/([^/]+)", {"GET"}, req)) { + BOOST_LOG_TRIVIAL(debug) << "GET TILE SET map request"; + return get_tileset(req, services, true); + } else if (tiles && match_route("/collections/([^/]+)/styles/([^/]+)/map/tiles/([^/]+)/([^/]+)/([^/]+)/([^/]+)", {"GET"}, req)) { + BOOST_LOG_TRIVIAL(debug) << "GET TILE map request"; + return get_tile(req, services, true); + } + + // MAPS + // Données raster + else if (maps && match_route("/collections/([^/]+)/map", {"GET"}, req)) { + BOOST_LOG_TRIVIAL(debug) << "GET MAP request"; + return get_map(req, services); + } else if (maps && match_route("/collections/([^/]+)/styles/([^/]+)/map", {"GET"}, req)) { + BOOST_LOG_TRIVIAL(debug) << "GET MAP request"; + return get_map(req, services); + } + + else { + throw OgcApiException::get_error_message("ResourceNotFound", "Unknown OGC API request path", 404); + } +}; diff --git a/src/services/tiles/Service.h b/src/services/ogcapi/Service.h similarity index 55% rename from src/services/tiles/Service.h rename to src/services/ogcapi/Service.h index 0c5d993..8b93d0b 100644 --- a/src/services/tiles/Service.h +++ b/src/services/ogcapi/Service.h @@ -38,50 +38,62 @@ /** * \file services/tiles/Service.h ** \~french - * \brief Définition de la classe TilesService + * \brief Définition de la classe OgcApiService ** \~english - * \brief Define classe TilesService + * \brief Define classe OgcApiService */ -class TilesService; +class OgcApiService; #pragma once #include "services/Service.h" -#include "configurations/Metadata.h" /** * \author Institut national de l'information géographique et forestière * \~french - * \brief Gestion du service OGC API Tiles du serveur + * \brief Gestion du service OGC API du serveur */ -class TilesService : public Service { +class OgcApiService : public Service { private: - DataStream* get_conformance ( Request* req, Rok4Server* serv ); - DataStream* get_landing_page ( Request* req, Rok4Server* serv ); + static std::vector common_conformances; + static std::vector maps_conformances; + static std::vector tiles_conformances; + static std::map ogcapi_format_to_mime_type; + + DataStream* get_landing_page ( Request* req, ServicesConfiguration* services ); + DataStream* get_conformance ( Request* req, ServicesConfiguration* services ); + + DataStream* get_api_collections ( Request* req, ServicesConfiguration* services ); + DataStream* get_api_vector_collections ( Request* req, ServicesConfiguration* services ); + DataStream* get_api_tilematrixsets ( Request* req, ServicesConfiguration* services ); + DataStream* get_api_styles ( Request* req, ServicesConfiguration* services ); + + DataStream* get_tilematrixsets ( Request* req, ServicesConfiguration* services ); + DataStream* get_tilematrixset ( Request* req, ServicesConfiguration* services ); /** * \todo Gérer la pagination - * \todo Filtrer selon la bbox */ - DataStream* get_capabilities ( Request* req, Rok4Server* serv ); - DataStream* get_tilematrixsets ( Request* req, Rok4Server* serv ); - DataStream* get_tilematrixset ( Request* req, Rok4Server* serv ); - DataStream* get_tiles ( Request* req, Rok4Server* serv ); - DataStream* get_feature_info ( Request* req, Rok4Server* serv ); - DataStream* get_styles ( Request* req, Rok4Server* serv); - DataStream* get_tilesets ( Request* req, Rok4Server* serv, bool is_map_request ); - DataStream* get_tileset ( Request* req, Rok4Server* serv, bool is_map_request ); - DataStream* get_tile ( Request* req, Rok4Server* serv, bool is_map_request ); - - Metadata* metadata; - bool reprojection; + DataStream* get_collections ( Request* req, ServicesConfiguration* services ); + DataStream* get_collection ( Request* req, ServicesConfiguration* services ); + + DataStream* get_tilesets ( Request* req, ServicesConfiguration* services, bool is_map_request ); + DataStream* get_tileset ( Request* req, ServicesConfiguration* services, bool is_map_request ); + DataStream* get_tile ( Request* req, ServicesConfiguration* services, bool is_map_request ); + + DataStream* get_map ( Request* req, ServicesConfiguration* services ); + + bool tiles; + bool maps; + + int default_size; std::string cache_getcapabilities; public: - DataStream* process_request(Request* req, Rok4Server* serv); + DataStream* process_request(Request* req, ServicesConfiguration* services ); /** * \~french @@ -89,7 +101,7 @@ class TilesService : public Service { * \~english * \brief Service constructor */ - TilesService (json11::Json& doc); + OgcApiService (json11::Json& doc); /** * \~french @@ -105,12 +117,22 @@ class TilesService : public Service { /** * \~french - * \brief La reprojection est-elle activée + * \brief L'API Tiles est-elle activée * \~english - * \brief Is reprojection enabled + * \brief Is API Tiles enabled */ - bool reprojection_enabled() { - return reprojection; + bool tiles_enabled() { + return tiles; + }; + + /** + * \~french + * \brief L'API Maps est-elle activée + * \~english + * \brief Is API Maps enabled + */ + bool maps_enabled() { + return maps; }; /** @@ -119,9 +141,7 @@ class TilesService : public Service { * \~english * \brief Destructor */ - ~TilesService() { - if (metadata) delete metadata; - }; + ~OgcApiService() {}; }; diff --git a/src/services/tiles/tilematrixsets.cpp b/src/services/ogcapi/api.cpp similarity index 54% rename from src/services/tiles/tilematrixsets.cpp rename to src/services/ogcapi/api.cpp index 7131306..1b1b8a1 100644 --- a/src/services/tiles/tilematrixsets.cpp +++ b/src/services/ogcapi/api.cpp @@ -38,22 +38,109 @@ /** * \file services/tiles/getcapabilities.cpp ** \~french - * \brief Implémentation de la classe TilesService + * \brief Implémentation de la classe OgcApiService ** \~english - * \brief Implements classe TilesService + * \brief Implements classe OgcApiService */ #include -#include "services/tiles/Exception.h" -#include "services/tiles/Service.h" -#include "Rok4Server.h" +#include "services/ogcapi/Exception.h" +#include "services/ogcapi/Service.h" +#include "core/Rok4Server.h" -DataStream* TilesService::get_tilematrixsets ( Request* req, Rok4Server* serv ) { + + +DataStream* OgcApiService::get_api_collections ( Request* req, ServicesConfiguration* services ) { + std::string f = req->get_query_param("f"); + if (f != "" && f != "application/json" && f != "json") { + throw OgcApiException::get_error_message("InvalidParameter", "Format unknown", 400); + } + + std::vector collections; + + for(auto const& l: services->get_layers()) { + if (l.second->is_ogcapi_enabled()) { + collections.push_back(l.first); + } + } + + json11::Json::object res = json11::Json::object { + { "type", "enum" }, + { "enum", collections } + }; + + return new MessageDataStream ( json11::Json{ res }.dump(), "application/json", 200 ); +} + +DataStream* OgcApiService::get_api_vector_collections ( Request* req, ServicesConfiguration* services ) { + + std::string f = req->get_query_param("f"); + if (f != "" && f != "application/json" && f != "json") { + throw OgcApiException::get_error_message("InvalidParameter", "Format unknown", 400); + } + + std::vector collections; + + for(auto const& l: services->get_layers()) { + if (l.second->is_ogcapi_enabled() && ! l.second->is_raster()) { + collections.push_back(l.first); + } + } + + json11::Json::object res = json11::Json::object { + { "type", "enum" }, + { "enum", collections } + }; + + return new MessageDataStream ( json11::Json{ res }.dump(), "application/json", 200 ); +} + +DataStream* OgcApiService::get_api_tilematrixsets ( Request* req, ServicesConfiguration* services ) { + + std::string f = req->get_query_param("f"); + if (f != "" && f != "application/json" && f != "json") { + throw OgcApiException::get_error_message("InvalidParameter", "Format unknown", 400); + } + + std::vector tms; + for(auto const& t: TmsBook::get_book()) { + tms.push_back(t.first); + } + + json11::Json::object res = json11::Json::object { + { "type", "enum" }, + { "enum", tms } + }; + + return new MessageDataStream ( json11::Json{ res }.dump(), "application/json", 200 ); +} + +DataStream* OgcApiService::get_api_styles ( Request* req, ServicesConfiguration* services ) { + + std::string f = req->get_query_param("f"); + if (f != "" && f != "application/json" && f != "json") { + throw OgcApiException::get_error_message("InvalidParameter", "Format unknown", 400); + } + + std::vector styles; + for(auto const& s: StyleBook::get_book()) { + styles.push_back(s.first); + } + + json11::Json::object res = json11::Json::object { + { "type", "enum" }, + { "enum", styles } + }; + + return new MessageDataStream ( json11::Json{ res }.dump(), "application/json", 200 ); +} + +DataStream* OgcApiService::get_tilematrixsets ( Request* req, ServicesConfiguration* services ) { std::string f = req->get_query_param("f"); if (f != "" && f != "application/json" && f != "json") { - throw TilesException::get_error_message("InvalidParameter", "Format unknown", 400); + throw OgcApiException::get_error_message("InvalidParameter", "Format unknown", 400); } json11::Json::object res = json11::Json::object {}; @@ -82,23 +169,23 @@ DataStream* TilesService::get_tilematrixsets ( Request* req, Rok4Server* serv ) } -DataStream* TilesService::get_tilematrixset ( Request* req, Rok4Server* serv ) { +DataStream* OgcApiService::get_tilematrixset ( Request* req, ServicesConfiguration* services ) { std::string f = req->get_query_param("f"); if (f != "" && f != "application/json" && f != "json") { - throw TilesException::get_error_message("InvalidParameter", "Format unknown", 400); + throw OgcApiException::get_error_message("InvalidParameter", "Format unknown", 400); } // Le TMS std::string str_tms = req->path_params.at(0); if ( contain_chars(str_tms, "\"")) { BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in TILES tms: " << str_tms ; - throw TilesException::get_error_message("ResourceNotFound", "Tile matrix set unknown", 404); + throw OgcApiException::get_error_message("ResourceNotFound", "Tile matrix set unknown", 404); } TileMatrixSet* tms = TmsBook::get_tms(str_tms); if ( tms == NULL) { - throw TilesException::get_error_message("ResourceNotFound", "Tile matrix set "+str_tms+" unknown", 404); + throw OgcApiException::get_error_message("ResourceNotFound", "Tile matrix set "+str_tms+" unknown", 404); } json11::Json::object res = json11::Json::object { diff --git a/src/services/ogcapi/capabilities.cpp b/src/services/ogcapi/capabilities.cpp new file mode 100644 index 0000000..b0b5a78 --- /dev/null +++ b/src/services/ogcapi/capabilities.cpp @@ -0,0 +1,146 @@ +/* + * Copyright © (2011-2013) Institut national de l'information + * géographique et forestière + * + * Géoportail SAV + * + * This software is a computer program whose purpose is to publish geographic + * data using OGC WMS and WMTS protocol. + * + * This software is governed by the CeCILL-C license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL-C + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * + * knowledge of the CeCILL-C license and that you accept its terms. + */ + +/** + * \file services/ogcapi/getcapabilities.cpp + ** \~french + * \brief Implémentation de la classe OgcApiService + ** \~english + * \brief Implements classe OgcApiService + */ + +#include + +#include "services/ogcapi/Exception.h" +#include "services/ogcapi/Service.h" +#include "core/Rok4Server.h" + +std::vector OgcApiService::common_conformances = { + "http://www.opengis.net/spec/ogcapi-common-1/1.0/conf/core", + "http://www.opengis.net/spec/ogcapi-common-1/1.0/conf/landing-page", + "http://www.opengis.net/spec/ogcapi-common-1/1.0/conf/json", + "http://www.opengis.net/spec/ogcapi-common-1/1.0/conf/oas30", + "http://www.opengis.net/spec/ogcapi-common-2/1.0/conf/collections" +}; + +std::vector OgcApiService::maps_conformances = { + "https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/core", + "https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/tilesets", + "https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/collections-selection", + "https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/crs", + "https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/projection", + "https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/collection-map", + "https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/dataset-map", + "https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/styled-map", + "https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/png", + "https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/jpeg", + "https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/tiff", + "https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/api-operations" +}; + +std::vector OgcApiService::tiles_conformances ={ + "http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/core", + "http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/tileset", + "http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/tilesets-list", + "http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/geodata-tilesets", + "http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/dataset-tilesets", + "http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/jpeg", + "http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/png", + "http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/mvt", + "http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/tiff" +}; + +DataStream* OgcApiService::get_landing_page ( Request* req, ServicesConfiguration* services ) { + std::string f = req->get_query_param("f"); + if (f != "" && f != "application/json" && f != "json") { + throw OgcApiException::get_error_message("InvalidParameter", "Format unknown", 400); + } + + std::vector links; + + links.push_back(json11::Json::object { + { "href", endpoint_uri}, + { "rel", "self"}, + { "type", "application/json"}, + { "title", "this document"} + }); + + links.push_back(json11::Json::object { + { "href", endpoint_uri + "/collections?f=json"}, + { "rel", "data"}, + { "type", "application/json"}, + { "title", "Information about the collections"} + }); + + links.push_back(json11::Json::object { + { "href", endpoint_uri + "/conformance?f=json"}, + { "rel", "data"}, + { "type", "application/json"}, + { "title", "OGC API conformance classes implemented by this service"} + }); + + json11::Json::object res = json11::Json::object { + { "title", title }, + { "description", abstract }, + { "links", links } + }; + + return new MessageDataStream ( json11::Json{ res }.dump(), "application/json", 200 ); +} + +DataStream* OgcApiService::get_conformance ( Request* req, ServicesConfiguration* services ) { + std::string f = req->get_query_param("f"); + if (f != "" && f != "application/json" && f != "json") { + throw OgcApiException::get_error_message("InvalidParameter", "Format unknown", 400); + } + + std::vector conformances = common_conformances; + + if (maps) { + conformances.insert(conformances.end(), maps_conformances.begin(), maps_conformances.end()); + } + + if (tiles) { + conformances.insert(conformances.end(), tiles_conformances.begin(), tiles_conformances.end()); + } + + json11::Json::object res = json11::Json::object { + { "conformsTo", conformances } + }; + + return new MessageDataStream ( json11::Json{ res }.dump(), "application/json", 200 ); +} diff --git a/src/services/ogcapi/collections.cpp b/src/services/ogcapi/collections.cpp new file mode 100644 index 0000000..a681ace --- /dev/null +++ b/src/services/ogcapi/collections.cpp @@ -0,0 +1,162 @@ +/* + * Copyright © (2011-2013) Institut national de l'information + * géographique et forestière + * + * Géoportail SAV + * + * This software is a computer program whose purpose is to publish geographic + * data using OGC WMS and WMTS protocol. + * + * This software is governed by the CeCILL-C license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL-C + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * + * knowledge of the CeCILL-C license and that you accept its terms. + */ + +/** + * \file services/ogcapi/getcapabilities.cpp + ** \~french + * \brief Implémentation de la classe OgcApiService + ** \~english + * \brief Implements classe OgcApiService + */ + +#include +#include + +#include "services/ogcapi/Exception.h" +#include "services/ogcapi/Service.h" +#include "core/Rok4Server.h" + + +DataStream* OgcApiService::get_collections ( Request* req, ServicesConfiguration* services ) { + + // format + std::string f = req->get_query_param("f"); + if (f != "" && f != "application/json" && f != "json") { + throw OgcApiException::get_error_message("InvalidParameter", "Format unknown", 400); + } + + // bbox + std::string str_bbox = req->get_query_param("bbox"); + bool bbox_provided = false; + BoundingBox bbox; + if (str_bbox != "") { + bbox_provided = true; + + std::vector vector_bbox; + boost::split(vector_bbox, str_bbox, boost::is_any_of(",")); + if (vector_bbox.size() != 4) throw OgcApiException::get_error_message("InvalidParameter", "Bbox invalid", 400); + + double bb[4]; + for ( int i = 0; i < 4; i++ ) { + if ( sscanf ( vector_bbox[i].c_str(),"%lf",&bb[i] ) !=1 ) + throw OgcApiException::get_error_message("InvalidParameter", "Bbox invalid", 400); + //Test NaN values + if (bb[i] != bb[i]) + throw OgcApiException::get_error_message("InvalidParameter", "Bbox invalid", 400); + } + if ( bb[0] >= bb[2] || bb[1] >= bb[3] ) + throw OgcApiException::get_error_message("InvalidParameter", "Bbox invalid", 400); + + bbox.xmin=bb[0]; + bbox.ymin=bb[1]; + bbox.xmax=bb[2]; + bbox.ymax=bb[3]; + } + + if ( ! cache_getcapabilities.empty() && ! bbox_provided) { + return new MessageDataStream ( cache_getcapabilities, "application/json", 200 ); + } + + std::vector links; + if (bbox_provided) { + links.push_back(json11::Json::object { + { "href", endpoint_uri + "/collections?f=json&bbox=" + str_bbox}, + { "rel", "self"}, + { "type", "application/json"}, + { "title", "this document"} + }); + } else { + links.push_back(json11::Json::object { + { "href", endpoint_uri + "/collections?f=json"}, + { "rel", "self"}, + { "type", "application/json"}, + { "title", "this document"} + }); + } + + if (metadata) { + links.push_back(metadata->to_json_ogcapi("Service metadata", "describedby")); + } + + std::vector collections; + + std::map::iterator layers_iterator ( services->get_layers().begin() ), layers_end ( services->get_layers().end() ); + for ( ; layers_iterator != layers_end; ++layers_iterator ) { + if (layers_iterator->second->is_ogcapi_enabled() && (! bbox_provided || layers_iterator->second->get_geographical_bbox().intersects(bbox))) { + collections.push_back(layers_iterator->second->to_json_ogcapi(this)); + } + } + + json11::Json::object res = json11::Json::object { + { "links", links }, + { "numberMatched", (int) collections.size() }, + { "numberReturned", (int) collections.size() } + }; + + res["collections"] = collections; + + if (! bbox_provided) { + cache_mtx.lock(); + cache_getcapabilities = json11::Json{ res }.dump(); + cache_mtx.unlock(); + return new MessageDataStream ( cache_getcapabilities, "application/json", 200 ); + } + return new MessageDataStream ( json11::Json{ res }.dump(), "application/json", 200 ); +} + + +DataStream* OgcApiService::get_collection ( Request* req, ServicesConfiguration* services ) { + + std::string f = req->get_query_param("f"); + if (f != "" && f != "application/json" && f != "json") { + throw OgcApiException::get_error_message("InvalidParameter", "Format unknown", 400); + } + + // La couche + std::string str_layer = req->path_params.at(0); + if ( contain_chars(str_layer, "\"")) { + BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in collection: " << str_layer ; + throw OgcApiException::get_error_message("ResourceNotFound", "Layer unknown", 404); + } + + Layer* layer = services->get_layer(str_layer); + if ( layer == NULL || ! layer->is_ogcapi_enabled() ) { + throw OgcApiException::get_error_message("ResourceNotFound", "Layer "+str_layer+" unknown", 404); + } + + return new MessageDataStream ( json11::Json{ layer->to_json_ogcapi(this) }.dump(), "application/json", 200 ); +} diff --git a/src/services/ogcapi/maps.cpp b/src/services/ogcapi/maps.cpp new file mode 100644 index 0000000..3d78c2b --- /dev/null +++ b/src/services/ogcapi/maps.cpp @@ -0,0 +1,304 @@ +/* + * Copyright © (2011-2013) Institut national de l'information + * géographique et forestière + * + * Géoportail SAV + * + * This software is a computer program whose purpose is to publish geographic + * data using OGC WMS and WMTS protocol. + * + * This software is governed by the CeCILL-C license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL-C + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * + * knowledge of the CeCILL-C license and that you accept its terms. + */ + +/** + * \file services/ogcapi/gettile.cpp + ** \~french + * \brief Implémentation de la classe OgcApiService + ** \~english + * \brief Implements classe OgcApiService + */ + +#include +#include + +#include "services/ogcapi/Exception.h" +#include "services/ogcapi/Service.h" +#include "core/Rok4Server.h" +#include "core/Map.h" + + +DataStream* OgcApiService::get_map ( Request* req, ServicesConfiguration* services ) { + + // La couche + std::string str_layer = req->path_params.at(0); + if ( contain_chars(str_layer, "\"")) { + BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in collection: " << str_layer ; + throw OgcApiException::get_error_message("ResourceNotFound", "Layer unknown", 404); + } + + Layer* layer = services->get_layer(str_layer); + if ( layer == NULL || ! layer->is_ogcapi_enabled() ) { + throw OgcApiException::get_error_message("ResourceNotFound", "Layer "+str_layer+" unknown", 404); + } + + if (! layer->is_raster()) { + throw OgcApiException::get_error_message("InvalidParameter", "Vector data " + str_layer + " cannot be requested with OGC API Maps", 400); + } + + std::vector layers = {layer}; + + // le CRS de l'image finale + CRS* crs; + std::string str_crs = req->get_query_param("crs"); + if (str_crs != "") { + if (contain_chars(str_crs, "\"")) { + BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in CRS: " << str_crs; + throw OgcApiException::get_error_message("InvalidParameter", "CRS unknown", 400); + } + } else { + str_crs = layer->get_native_bbox().crs; + } + + crs = CrsBook::get_crs( str_crs ); + if (! crs->is_define()) { + throw OgcApiException::get_error_message("InvalidParameter", "CRS " + str_crs + " unknown", 400); + } + + if (! services->is_map_available_crs(str_crs) ) { + for ( unsigned int i = 0; i < layers.size() ; i++ ) { + bool crs_equals = services->are_crs_equals(crs->get_request_code(), layers.at(i)->get_pyramid()->get_tms()->get_crs()->get_request_code()); + if (! crs_equals && (! services->map_reprojection || ! layers.at ( i )->is_available_crs(str_crs)) ) { + throw OgcApiException::get_error_message("InvalidParameter", "CRS " + str_crs + " is not available for the layer " + layers.at ( i )->get_id(), 400); + } + } + } + + // le CRS de la bbox + CRS* bbox_crs; + std::string str_bbox_crs = req->get_query_param("bbox-crs"); + if (str_bbox_crs != "") { + if (contain_chars(str_bbox_crs, "\"")) { + BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in CRS: " << str_bbox_crs; + throw OgcApiException::get_error_message("InvalidParameter", "CRS unknown", 400); + } + } else { + str_bbox_crs = "CRS:84"; + } + + bbox_crs = CrsBook::get_crs( str_bbox_crs ); + if (! bbox_crs->is_define()) { + throw OgcApiException::get_error_message("InvalidParameter", "BBOX CRS " + str_bbox_crs + " unknown", 400); + } + + if (! services->is_map_available_crs(str_bbox_crs) ) { + for ( unsigned int i = 0; i < layers.size() ; i++ ) { + bool crs_equals = services->are_crs_equals(bbox_crs->get_request_code(), layers.at(i)->get_pyramid()->get_tms()->get_crs()->get_request_code()); + if (! crs_equals && (! services->map_reprojection || ! layers.at ( i )->is_available_crs(str_bbox_crs)) ) { + throw OgcApiException::get_error_message("InvalidParameter", "BBOX CRS " + str_bbox_crs + " is not available for the layer " + layers.at ( i )->get_id(), 400); + } + } + } + + // La bbox + std::string str_bbox = req->get_query_param("bbox"); + BoundingBox bbox; + if (str_bbox != "") { + + std::vector vector_bbox; + boost::split(vector_bbox, str_bbox, boost::is_any_of(",")); + if (vector_bbox.size() != 4 && vector_bbox.size() != 6) throw OgcApiException::get_error_message("InvalidParameter", "bbox query parameter invalid (require 4 or 6 comma separated numbers)", 400); + + if (vector_bbox.size() == 6) { + // On retire le 6ème et le 3ème élément + vector_bbox.erase(vector_bbox.begin() + 5); + vector_bbox.erase(vector_bbox.begin() + 2); + } + + double bb[4]; + for ( int i = 0; i < 4; i++ ) { + if ( sscanf ( vector_bbox[i].c_str(),"%lf",&bb[i] ) !=1 ) + throw OgcApiException::get_error_message("InvalidParameter", "BBOX query parameter invalid (require 4 or 6 comma separated numbers)", 400); + //Test NaN values + if (bb[i] != bb[i]) + throw OgcApiException::get_error_message("InvalidParameter", "BBOX query parameter invalid (require 4 or 6 comma separated numbers)", 400); + } + if ( bb[0] >= bb[2] || bb[1] >= bb[3] ) + throw OgcApiException::get_error_message("InvalidParameter", "BBOX query parameter invalid (max have to be bigger than min)", 400); + + if (bbox_crs->is_lat_lon()) { + bbox.xmin=bb[1]; + bbox.ymin=bb[0]; + bbox.xmax=bb[3]; + bbox.ymax=bb[2]; + } else { + bbox.xmin=bb[0]; + bbox.ymin=bb[1]; + bbox.xmax=bb[2]; + bbox.ymax=bb[3]; + } + + bbox.crs = bbox_crs->get_request_code(); + } else { + // On met la bbox globale de la donnée, dans le CRS natif des données + bbox = layer->get_native_bbox(); + bbox.crs = layer->get_pyramid()->get_tms()->get_crs()->get_request_code(); + str_bbox_crs = layer->get_pyramid()->get_tms()->get_crs()->get_request_code(); + bbox_crs = layer->get_pyramid()->get_tms()->get_crs(); + } + + // Reprojection de la bbox dans le CRS de l'image demandée + + if (! services->are_crs_equals(str_bbox_crs, str_crs)) { + bbox.reproject(bbox_crs, crs, 4); + } + + // calcul du ratio largeur sur hauteur de la bbox + double bbox_ratio = (bbox.xmax - bbox.xmin) / (bbox.ymax - bbox.ymin); + + // Dimensions + + int width = -1; + std::string str_width = req->get_query_param("width"); + + if (str_width != "") { + if (sscanf(str_width.c_str(), "%d", &width) != 1) + throw OgcApiException::get_error_message("InvalidParameter", "Invalid width value", 400); + + if ( width <= 0 ) + throw OgcApiException::get_error_message("InvalidParameter", "width query parameter have to be a strictly positive integer", 400); + if ( width > services->map_max_width ) + throw OgcApiException::get_error_message("InvalidParameter", "width query parameter exceed the limit (" + std::to_string(services->map_max_width) + ")", 400); + } + + int height = -1; + std::string str_height = req->get_query_param("height"); + if (str_height != "") { + if (sscanf(str_height.c_str(), "%d", &height) != 1) + throw OgcApiException::get_error_message("InvalidParameter", "Invalid height value", 400); + + if ( height <= 0 ) + throw OgcApiException::get_error_message("InvalidParameter", "height query parameter have to be a strictly positive integer", 400); + if ( height > services->map_max_height ) + throw OgcApiException::get_error_message("InvalidParameter", "height query parameter exceed the limit (" + std::to_string(services->map_max_height) + ")", 400); + } + + if (width == -1 && height == -1) { + // On a fourni aucune dimension, on met la plus grande à default_size et l'autre en respectant le ratio + if (bbox.xmax - bbox.xmin > bbox.ymax - bbox.ymin) { + width = default_size; + } else { + height = default_size; + } + } + + if (width == -1) { + // Une dimension est encore manquante, on respecte le ratio pour la définir + width = (int) round(bbox_ratio * height); + } + else if (height == -1) { + // Une dimension est encore manquante, on respecte le ratio pour la définir + height = (int) round((double) width / bbox_ratio); + } + + // Le format + std::string str_format = req->get_query_param("f"); + std::string format; + if (str_format != "") { + + if (contain_chars(str_format, "\"")) { + // On a détecté un caractère interdit, on ne met pas le format fourni dans la réponse pour éviter une injection + BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in OGC API Maps format: " << str_format; + throw OgcApiException::get_error_message("InvalidParameter", "Format unknown", 400); + } + + if (ogcapi_format_to_mime_type.find(str_format) == ogcapi_format_to_mime_type.end()) { + throw OgcApiException::get_error_message("InvalidParameter", "Format " + str_format + " unknown", 400); + } + + format = ogcapi_format_to_mime_type.at(str_format); + + if (! services->is_map_available_format(format)) { + throw OgcApiException::get_error_message("InvalidParameter", "Format " + str_format + " unknown", 400); + } + } else { + format = Rok4Format::to_mime_type(layer->get_pyramid()->get_format()); + } + + // Le style + std::vector styles; + + if (req->path_params.size() == 1) { + // pas de style fourni, on prend celui par défaut + styles.push_back(layer->get_default_style()); + } else { + std::string str_style = req->path_params.at(1); + if (contain_chars(str_style, "\"")) { + // On a détecté un caractère interdit, on ne met pas le style fourni dans la réponse pour éviter une injection + BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in OGC API Maps style: " << str_style; + throw OgcApiException::get_error_message("InvalidParameter", "Style unknown", 400); + } + + Style* style = layer->get_style_by_identifier(str_style); + if ( style == NULL ) + throw OgcApiException::get_error_message("InvalidParameter", "Style " + str_style + " is not available for the layer " + layer->get_id(), 400); + + styles.push_back(style); + } + + // Les options de format (non géré dans OGC API Maps) + std::map format_options ; + + // La résolution + double res = 0; + int dpi = 0; + std::string str_res = req->get_query_param("mm-per-pixel"); + if (str_res != "") { + if (sscanf(str_res.c_str(), "%lf", &res) != 1) + throw OgcApiException::get_error_message("InvalidParameter", "Invalid mm-per-pixel value", 400); + + if ( res <= 0 ) + throw OgcApiException::get_error_message("InvalidParameter", "mm-per-pixel query parameter have to be a strictly positive number", 400); + + dpi = (int) round(25.4 / res); + } else { + res = 0.28; + } + + + // Traitement de la requête + std::string error; + DataStream* d = Map::get_map( + services, services->map_reprojection, services->map_max_tile_x, services->map_max_tile_y, + layers, width, height, crs, bbox, styles, format, format_options, dpi, + &error + ); + if (d == NULL) { + throw OgcApiException::get_error_message("InvalidParameter", error, 400); + } + return d; +} \ No newline at end of file diff --git a/src/services/ogcapi/tiles.cpp b/src/services/ogcapi/tiles.cpp new file mode 100644 index 0000000..edab074 --- /dev/null +++ b/src/services/ogcapi/tiles.cpp @@ -0,0 +1,293 @@ +/* + * Copyright © (2011-2013) Institut national de l'information + * géographique et forestière + * + * Géoportail SAV + * + * This software is a computer program whose purpose is to publish geographic + * data using OGC WMS and WMTS protocol. + * + * This software is governed by the CeCILL-C license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL-C + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * + * knowledge of the CeCILL-C license and that you accept its terms. + */ + +/** + * \file services/ogcapi/gettile.cpp + ** \~french + * \brief Implémentation de la classe OgcApiService + ** \~english + * \brief Implements classe OgcApiService + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "services/ogcapi/Exception.h" +#include "services/ogcapi/Service.h" +#include "core/Rok4Server.h" +#include "core/Tile.h" + + +DataStream* OgcApiService::get_tilesets ( Request* req, ServicesConfiguration* services, bool is_map_request ) { + + std::string f = req->get_query_param("f"); + if (f != "" && f != "application/json" && f != "json") { + throw OgcApiException::get_error_message("InvalidParameter", "Format unknown", 400); + } + + // La couche + std::string str_layer = req->path_params.at(0); + if ( contain_chars(str_layer, "\"")) { + BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in collection: " << str_layer ; + throw OgcApiException::get_error_message("ResourceNotFound", "Layer unknown", 404); + } + + Layer* layer = services->get_layer(str_layer); + if ( layer == NULL || ! layer->is_ogcapi_enabled() ) { + throw OgcApiException::get_error_message("ResourceNotFound", "Layer "+str_layer+" unknown", 404); + } + + bool is_raster_data = layer->is_raster(); + + if (is_map_request) { + // Map tiles request -> pour les pyramides raster + if (! is_raster_data) { + throw OgcApiException::get_error_message("InvalidParameter", "Vector dataset have to be requested without map", 400); + } + + } else { + // Tiles request -> pour les pyramides vecteur + if (is_raster_data) { + throw OgcApiException::get_error_message("InvalidParameter", "Raster dataset have to be requested with map", 400); + } + } + + return new MessageDataStream ( json11::Json{ layer->to_json_tilesets(this) }.dump(), "application/json", 200 ); +} + + +DataStream* OgcApiService::get_tileset ( Request* req, ServicesConfiguration* services, bool is_map_request ) { + + std::string f = req->get_query_param("f"); + if (f != "" && f != "application/json" && f != "json") { + throw OgcApiException::get_error_message("InvalidParameter", "Format unknown", 400); + } + + // La couche + std::string str_layer = req->path_params.at(0); + if ( contain_chars(str_layer, "\"")) { + BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in collection: " << str_layer ; + throw OgcApiException::get_error_message("ResourceNotFound", "Layer unknown", 404); + } + + Layer* layer = services->get_layer(str_layer); + if ( layer == NULL || ! layer->is_ogcapi_enabled() ) { + throw OgcApiException::get_error_message("ResourceNotFound", "Layer "+str_layer+" unknown", 404); + } + + bool is_raster_data = layer->is_raster(); + + std::string str_tms; + + if (is_map_request) { + // Map tiles request -> pour les pyramides raster + if (! is_raster_data) { + throw OgcApiException::get_error_message("InvalidParameter", "Vector dataset have to be requested without map", 400); + } + + str_tms = req->path_params.at(1); + + } else { + // Tiles request -> pour les pyramides vecteur + if (is_raster_data) { + throw OgcApiException::get_error_message("InvalidParameter", "Raster dataset have to be requested with map", 400); + } + + str_tms = req->path_params.at(1); + } + + // Le tile matrix set + if (contain_chars(str_tms, "\"")) { + BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in TILES tile matrix set: " << str_tms; + throw OgcApiException::get_error_message("InvalidParameter", "Tile matrix set unknown", 400); + } + + TileMatrixSetInfos* tmsi = layer->get_tilematrixset(str_tms); + if (tmsi == NULL || (! services->tile_reprojection && tmsi->tms->get_id() != layer->get_pyramid()->get_tms()->get_id())) { + throw OgcApiException::get_error_message("InvalidParameter", "Tile matrix set " + str_tms + " unknown", 400); + } + + return new MessageDataStream ( json11::Json{ layer->to_json_tileset(this, tmsi) }.dump(), "application/json", 200 ); +} + +DataStream* OgcApiService::get_tile ( Request* req, ServicesConfiguration* services, bool is_map_request ) { + + // La couche + std::string str_layer = req->path_params.at(0); + if ( contain_chars(str_layer, "\"")) { + BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in collection: " << str_layer ; + throw OgcApiException::get_error_message("ResourceNotFound", "Layer unknown", 404); + } + + Layer* layer = services->get_layer(str_layer); + if ( layer == NULL || ! layer->is_ogcapi_enabled() ) { + throw OgcApiException::get_error_message("ResourceNotFound", "Layer "+str_layer+" unknown", 404); + } + + bool is_raster_data = layer->is_raster(); + + // Le format : mvt, png, jpg ou tiff si fourni + // Le format doit correspondre à celui natif des données + + std::string format; + + if (! req->has_query_param("f")) { + format = Rok4Format::to_ogcapi_format(layer->get_pyramid()->get_format()); + } else { + format = req->get_query_param("f"); + + if (contain_chars(format, "\"")) { + BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in format: " << format ; + throw OgcApiException::get_error_message("InvalidParameter", "Format unknown", 400); + } + + if (format != Rok4Format::to_ogcapi_format(layer->get_pyramid()->get_format())) { + throw OgcApiException::get_error_message("InvalidParameter", "Format " + format + " unknown", 400); + } + } + + format = ogcapi_format_to_mime_type.at(format); + + // Récupération des paramètre selon le type de route (raster ou vecteur) + + std::string str_tms; + std::string str_tm; + std::string str_row; + std::string str_column; + + Style* style = NULL; + + if (is_map_request) { + // Map tiles request -> pour les pyramides raster + if (! is_raster_data) { + throw OgcApiException::get_error_message("InvalidParameter", "Vector dataset have to be requested with tiles request", 400); + } + + std::string str_style = req->path_params.at(1); + str_tms = req->path_params.at(2); + str_tm = req->path_params.at(3); + str_row = req->path_params.at(4); + str_column = req->path_params.at(5); + + // Traitement du style + if ( contain_chars(str_style, "\"")) { + BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in style: " << str_layer ; + throw OgcApiException::get_error_message("InvalidParameter", "Style unknown", 400); + } + + style = layer->get_style_by_identifier(str_style); + + if (style == NULL) { + throw OgcApiException::get_error_message("InvalidParameter", "Style " + str_style + " unknown", 400); + } + + } else { + // Tiles request -> pour les pyramides vecteur + if (is_raster_data) { + throw OgcApiException::get_error_message("InvalidParameter", "Raster dataset have to be requested with map tiles request", 400); + } + + str_tms = req->path_params.at(1); + str_tm = req->path_params.at(2); + str_row = req->path_params.at(3); + str_column = req->path_params.at(4); + } + + // Le tile matrix set + if (contain_chars(str_tms, "\"")) { + BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in tile matrix set: " << str_tms; + throw OgcApiException::get_error_message("InvalidParameter", "Tile matrix set unknown", 400); + } + + TileMatrixSetInfos* tmsi = layer->get_tilematrixset(str_tms); + if (tmsi == NULL) { + throw OgcApiException::get_error_message("InvalidParameter", "Tile matrix set " + str_tms + " unknown", 400); + } + if (tmsi->tms->get_id() != layer->get_pyramid()->get_tms()->get_id() && ! services->tile_reprojection) { + throw OgcApiException::get_error_message("InvalidParameter", "Tile matrix set " + str_tms + " unknown", 400); + } + + // Le niveau + if (contain_chars(str_tm, "\"")) { + BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in tile matrix: " << str_tm; + throw OgcApiException::get_error_message("InvalidParameter", "Tile matrix unknown", 400); + } + + TileMatrix* tm = tmsi->tms->get_tm(str_tm); + if (tm == NULL) { + throw OgcApiException::get_error_message("InvalidParameter", "Tile matrix " + str_tm + " unknown", 400); + } + + // La colonne + int column; + if (sscanf(str_column.c_str(), "%d", &column) != 1) { + throw OgcApiException::get_error_message("InvalidParameter", "Invalid column value", 400); + } + + // La ligne + int row; + if (sscanf(str_row.c_str(), "%d", &row) != 1) { + throw OgcApiException::get_error_message("InvalidParameter", "Invalid row value", 400); + } + + TileMatrixLimits* tml = layer->get_tilematrix_limits(tmsi->tms, tm); + if (tml == NULL) { + // On est hors niveau -> erreur + throw OgcApiException::get_error_message("ResourceNotFound", "Level out of limits", 404); + } + if (!tml->contain_tile(column, row)) { + // On est hors tuiles -> erreur + throw OgcApiException::get_error_message("ResourceNotFound", "Tile's indices out of limits", 404); + } + + // Traitement de la requête + DataStream* d = Tile::get_tile(services, layer, tmsi->tms, tm, column, row, format, style); + if (d == NULL) { + throw OgcApiException::get_error_message("ResourceNotFound", "Not data found", 404); + } + return d; +} \ No newline at end of file diff --git a/src/services/tiles/Exception.cpp b/src/services/tiles/Exception.cpp deleted file mode 100644 index 9981f3d..0000000 --- a/src/services/tiles/Exception.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright © (2011-2013) Institut national de l'information - * géographique et forestière - * - * Géoportail SAV - * - * This software is a computer program whose purpose is to publish geographic - * data using OGC WMS and WMTS protocol. - * - * This software is governed by the CeCILL-C license under French law and - * abiding by the rules of distribution of free software. You can use, - * modify and/ or redistribute the software under the terms of the CeCILL-C - * license as circulated by CEA, CNRS and INRIA at the following URL - * "http://www.cecill.info". - * - * As a counterpart to the access to the source code and rights to copy, - * modify and redistribute granted by the license, users are provided only - * with a limited warranty and the software's author, the holder of the - * economic rights, and the successive licensors have only limited - * liability. - * - * In this respect, the user's attention is drawn to the risks associated - * with loading, using, modifying and/or developing or reproducing the - * software by the user in light of its specific status of free software, - * that may mean that it is complicated to manipulate, and that also - * therefore means that it is reserved for developers and experienced - * professionals having in-depth computer knowledge. Users are therefore - * encouraged to load and test the software's suitability as regards their - * requirements in conditions enabling the security of their systems and/or - * data to be ensured and, more generally, to use and operate it in the - * same conditions as regards security. - * - * The fact that you are presently reading this means that you have had - * - * knowledge of the CeCILL-C license and that you accept its terms. - */ - -/** - * \file services/tiles/Exception.cpp - ** \~french - * \brief Implémentation de la classe TilesException - ** \~english - * \brief Implements classe TilesException - */ - -#include "services/tiles/Exception.h" - -std::string TilesException::json_template = "{ \"type\": \"%s\", \"title\": \"%s\", \"status\": %s }"; - -MessageDataStream* TilesException::get_error_message(std::string type, std::string title, int status) { - return new MessageDataStream(str(boost::format(json_template) % type % title % status), "application/json", status); -} \ No newline at end of file diff --git a/src/services/tiles/Service.cpp b/src/services/tiles/Service.cpp deleted file mode 100644 index c1b9158..0000000 --- a/src/services/tiles/Service.cpp +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright © (2011-2013) Institut national de l'information - * géographique et forestière - * - * Géoportail SAV - * - * This software is a computer program whose purpose is to publish geographic - * data using OGC WMS and WMTS protocol. - * - * This software is governed by the CeCILL-C license under French law and - * abiding by the rules of distribution of free software. You can use, - * modify and/ or redistribute the software under the terms of the CeCILL-C - * license as circulated by CEA, CNRS and INRIA at the following URL - * "http://www.cecill.info". - * - * As a counterpart to the access to the source code and rights to copy, - * modify and redistribute granted by the license, users are provided only - * with a limited warranty and the software's author, the holder of the - * economic rights, and the successive licensors have only limited - * liability. - * - * In this respect, the user's attention is drawn to the risks associated - * with loading, using, modifying and/or developing or reproducing the - * software by the user in light of its specific status of free software, - * that may mean that it is complicated to manipulate, and that also - * therefore means that it is reserved for developers and experienced - * professionals having in-depth computer knowledge. Users are therefore - * encouraged to load and test the software's suitability as regards their - * requirements in conditions enabling the security of their systems and/or - * data to be ensured and, more generally, to use and operate it in the - * same conditions as regards security. - * - * The fact that you are presently reading this means that you have had - * - * knowledge of the CeCILL-C license and that you accept its terms. - */ - -/** - * \file services/tiles/Service.cpp - ** \~french - * \brief Implémentation de la classe TilesService - ** \~english - * \brief Implements classe TilesService - */ - -#include - -#include "services/tiles/Exception.h" -#include "services/tiles/Service.h" -#include "Rok4Server.h" - -TilesService::TilesService (json11::Json& doc) : Service(doc), metadata(NULL) { - - if (! is_ok()) { - // Le constructeur du service générique a détecté une erreur, on ajoute simplement le service concerné dans le message - error_message = "TILES service: " + error_message; - return; - } - - if (doc.is_null()) { - // Le service a déjà été mis comme n'étant pas actif - return; - } - - if (doc["title"].is_string()) { - title = doc["title"].string_value(); - } else if (! doc["title"].is_null()) { - error_message = "TILES service: title have to be a string"; - return; - } else { - title = "TILES service"; - } - - if (doc["abstract"].is_string()) { - abstract = doc["abstract"].string_value(); - } else if (! doc["abstract"].is_null()) { - error_message = "TILES service: abstract have to be a string"; - return; - } else { - abstract = "TILES service"; - } - - if (doc["keywords"].is_array()) { - for (json11::Json kw : doc["keywords"].array_items()) { - if (kw.is_string()) { - keywords.push_back(Keyword ( kw.string_value())); - } else { - error_message = "TILES service: keywords have to be a string array"; - return; - } - } - } else if (! doc["keywords"].is_null()) { - error_message = "TILES service: keywords have to be a string array"; - return; - } - - if (doc["endpoint_uri"].is_string()) { - endpoint_uri = doc["endpoint_uri"].string_value(); - } else if (! doc["endpoint_uri"].is_null()) { - error_message = "TILES service: endpoint_uri have to be a string"; - return; - } else { - endpoint_uri = "http://localhost/tiles"; - } - - if (doc["root_path"].is_string()) { - root_path = doc["root_path"].string_value(); - } else if (! doc["root_path"].is_null()) { - error_message = "TILES service: root_path have to be a string"; - return; - } else { - root_path = "/tiles"; - } - - if (doc["metadata"].is_object()) { - metadata = new Metadata ( doc["metadata"] ); - if (metadata->get_missing_field() != "") { - error_message = "TILES service: invalid metadata: have to own a field " + metadata->get_missing_field(); - return ; - } - } - - if (doc["reprojection"].is_bool()) { - reprojection = doc["reprojection"].bool_value(); - } else if (! doc["reprojection"].is_null()) { - error_message = "WMTS service: reprojection have to be a boolean"; - return; - } else { - reprojection = false; - } -} - -DataStream* TilesService::process_request(Request* req, Rok4Server* serv) { - BOOST_LOG_TRIVIAL(debug) << "TILES service"; - - if ( match_route( "", {"GET"}, req ) ) { - BOOST_LOG_TRIVIAL(debug) << "GETLANDINGPAGE request"; - return get_landing_page(req, serv); - } - else if ( match_route( "/conformance", {"GET"}, req ) ) { - BOOST_LOG_TRIVIAL(debug) << "GETCONFORMANCE request"; - return get_conformance(req, serv); - } - else if ( match_route( "/collections", {"GET"}, req ) ) { - BOOST_LOG_TRIVIAL(debug) << "GETCAPABILITIES request"; - return get_capabilities(req, serv); - } - else if ( match_route( "/tileMatrixSets", {"GET"}, req ) ) { - BOOST_LOG_TRIVIAL(debug) << "GETTILEMATRIXSETS request"; - return get_tilematrixsets(req, serv); - } - else if ( match_route( "/tileMatrixSets/([^/]+)", {"GET"}, req ) ) { - BOOST_LOG_TRIVIAL(debug) << "GETTILEMATRIXSET request"; - return get_tilematrixset(req, serv); - } - else if ( match_route( "/collections/([^/]+)", {"GET"}, req ) ) { - BOOST_LOG_TRIVIAL(debug) << "GETTILES request"; - return get_tiles(req, serv); - } - // Données vecteur - else if ( match_route( "/collections/([^/]+)/tiles", {"GET"}, req ) ) { - BOOST_LOG_TRIVIAL(debug) << "GETTILESETS vector request"; - return get_tilesets(req, serv, false); - } - else if ( match_route( "/collections/([^/]+)/tiles/([^/]+)", {"GET"}, req ) ) { - BOOST_LOG_TRIVIAL(debug) << "GETTILESET vector request"; - return get_tileset(req, serv, false); - } - else if ( match_route( "/collections/([^/]+)/tiles/([^/]+)/([^/]+)/([^/]+)/([^/]+)", {"GET"}, req ) ) { - BOOST_LOG_TRIVIAL(debug) << "GETTILE vector request"; - return get_tile(req, serv, false); - } - // Données raster - else if ( match_route( "/collections/([^/]+)/styles", {"GET"}, req ) ) { - BOOST_LOG_TRIVIAL(debug) << "GETSTYLES map request"; - return get_styles(req, serv); - } - else if ( match_route( "/collections/([^/]+)/styles/([^/]+)/map/tiles", {"GET"}, req ) ) { - BOOST_LOG_TRIVIAL(debug) << "GETTILESETS map request"; - return get_tilesets(req, serv, true); - } - else if ( match_route( "/collections/([^/]+)/styles/([^/]+)/map/tiles/([^/]+)", {"GET"}, req ) ) { - BOOST_LOG_TRIVIAL(debug) << "GETTILESET map request"; - return get_tileset(req, serv, true); - } - else if ( match_route( "/collections/([^/]+)/styles/([^/]+)/map/tiles/([^/]+)/([^/]+)/([^/]+)/([^/]+)", {"GET"}, req ) ) { - BOOST_LOG_TRIVIAL(debug) << "GETTILE map request"; - return get_tile(req, serv, true); - } - else if ( match_route( "/collections/([^/]+)/styles/([^/]+)/map/tiles/([^/]+)/([^/]+)/([^/]+)/([^/]+)/info", {"GET"}, req ) ) { - BOOST_LOG_TRIVIAL(debug) << "GETFEATUREINFO request"; - return get_feature_info(req, serv); - } else { - throw TilesException::get_error_message("ResourceNotFound", "Unknown tiles request path", 404); - } -}; diff --git a/src/services/tiles/getcapabilities.cpp b/src/services/tiles/getcapabilities.cpp deleted file mode 100644 index 4d0312f..0000000 --- a/src/services/tiles/getcapabilities.cpp +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright © (2011-2013) Institut national de l'information - * géographique et forestière - * - * Géoportail SAV - * - * This software is a computer program whose purpose is to publish geographic - * data using OGC WMS and WMTS protocol. - * - * This software is governed by the CeCILL-C license under French law and - * abiding by the rules of distribution of free software. You can use, - * modify and/ or redistribute the software under the terms of the CeCILL-C - * license as circulated by CEA, CNRS and INRIA at the following URL - * "http://www.cecill.info". - * - * As a counterpart to the access to the source code and rights to copy, - * modify and redistribute granted by the license, users are provided only - * with a limited warranty and the software's author, the holder of the - * economic rights, and the successive licensors have only limited - * liability. - * - * In this respect, the user's attention is drawn to the risks associated - * with loading, using, modifying and/or developing or reproducing the - * software by the user in light of its specific status of free software, - * that may mean that it is complicated to manipulate, and that also - * therefore means that it is reserved for developers and experienced - * professionals having in-depth computer knowledge. Users are therefore - * encouraged to load and test the software's suitability as regards their - * requirements in conditions enabling the security of their systems and/or - * data to be ensured and, more generally, to use and operate it in the - * same conditions as regards security. - * - * The fact that you are presently reading this means that you have had - * - * knowledge of the CeCILL-C license and that you accept its terms. - */ - -/** - * \file services/tiles/getcapabilities.cpp - ** \~french - * \brief Implémentation de la classe TilesService - ** \~english - * \brief Implements classe TilesService - */ - -#include - -#include "services/tiles/Exception.h" -#include "services/tiles/Service.h" -#include "Rok4Server.h" - - -DataStream* TilesService::get_landing_page ( Request* req, Rok4Server* serv ) { - std::string f = req->get_query_param("f"); - if (f != "" && f != "application/json" && f != "json") { - throw TilesException::get_error_message("InvalidParameter", "Format unknown", 400); - } - - std::vector links; - - links.push_back(json11::Json::object { - { "href", endpoint_uri}, - { "rel", "self"}, - { "type", "application/json"}, - { "title", "this document"} - }); - - links.push_back(json11::Json::object { - { "href", endpoint_uri + "/collections?f=json"}, - { "rel", "data"}, - { "type", "application/json"}, - { "title", "Information about the collections"} - }); - - links.push_back(json11::Json::object { - { "href", endpoint_uri + "/conformance?f=json"}, - { "rel", "data"}, - { "type", "application/json"}, - { "title", "OGC API conformance classes implemented by this service"} - }); - - json11::Json::object res = json11::Json::object { - { "title", title }, - { "description", abstract }, - { "links", links } - }; - - return new MessageDataStream ( json11::Json{ res }.dump(), "application/json", 200 ); -} - -DataStream* TilesService::get_conformance ( Request* req, Rok4Server* serv ) { - std::string f = req->get_query_param("f"); - if (f != "" && f != "application/json" && f != "json") { - throw TilesException::get_error_message("InvalidParameter", "Format unknown", 400); - } - - json11::Json::object res = json11::Json::object { - { "conformsTo", json11::Json::array{ - "http://www.opengis.net/spec/ogcapi-common-1/1.0/conf/core", - "http://www.opengis.net/spec/ogcapi-common-1/1.0/conf/json", - "http://www.opengis.net/spec/ogcapi-common-1/1.0/conf/oas30", - "http://www.opengis.net/spec/ogcapi-common-2/1.0/conf/collections", - "http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/core", - "http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/tileset", - "http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/tilesets-list", - "http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/geodata-tilesets", - "http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/dataset-tilesets", - "http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/jpeg", - "http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/png", - "http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/mvt", - "http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/tiff" - } } - }; - - return new MessageDataStream ( json11::Json{ res }.dump(), "application/json", 200 ); -} - -DataStream* TilesService::get_capabilities ( Request* req, Rok4Server* serv ) { - - std::string f = req->get_query_param("f"); - if (f != "" && f != "application/json" && f != "json") { - throw TilesException::get_error_message("InvalidParameter", "Format unknown", 400); - } - - if ( ! cache_getcapabilities.empty()) { - return new MessageDataStream ( cache_getcapabilities, "application/json", 200 ); - } - - std::vector links; - links.push_back(json11::Json::object { - { "href", endpoint_uri + "/collections?f=json"}, - { "rel", "self"}, - { "type", "application/json"}, - { "title", "this document"} - }); - - if (metadata) { - links.push_back(metadata->to_json_tiles("Service metadata", "describedby")); - } - - std::vector collections; - - std::map::iterator layers_iterator ( serv->get_server_configuration()->get_layers().begin() ), layers_end ( serv->get_server_configuration()->get_layers().end() ); - for ( ; layers_iterator != layers_end; ++layers_iterator ) { - if (layers_iterator->second->is_tiles_enabled()) { - collections.push_back(layers_iterator->second->to_json_tiles(this)); - } - } - - json11::Json::object res = json11::Json::object { - { "links", links }, - { "numberMatched", (int) collections.size() }, - { "numberReturned", (int) collections.size() } - }; - - res["collections"] = collections; - - cache_mtx.lock(); - cache_getcapabilities = json11::Json{ res }.dump(); - cache_mtx.unlock(); - return new MessageDataStream ( cache_getcapabilities, "application/json", 200 ); -} - -DataStream* TilesService::get_tiles ( Request* req, Rok4Server* serv ) { - - std::string f = req->get_query_param("f"); - if (f != "" && f != "application/json" && f != "json") { - throw TilesException::get_error_message("InvalidParameter", "Format unknown", 400); - } - - // La couche - std::string str_layer = req->path_params.at(0); - if ( contain_chars(str_layer, "\"")) { - BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in TILES layer: " << str_layer ; - throw TilesException::get_error_message("ResourceNotFound", "Layer unknown", 404); - } - - Layer* layer = serv->get_server_configuration()->get_layer(str_layer); - if ( layer == NULL || ! layer->is_tiles_enabled() ) { - throw TilesException::get_error_message("ResourceNotFound", "Layer "+str_layer+" unknown", 404); - } - - return new MessageDataStream ( json11::Json{ layer->to_json_tiles(this) }.dump(), "application/json", 200 ); -} - -DataStream* TilesService::get_styles ( Request* req, Rok4Server* serv ) { - - std::string f = req->get_query_param("f"); - if (f != "" && f != "application/json" && f != "json") { - throw TilesException::get_error_message("InvalidParameter", "Format unknown", 400); - } - - // La couche - std::string str_layer = req->path_params.at(0); - if ( contain_chars(str_layer, "\"")) { - BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in TILES layer: " << str_layer ; - throw TilesException::get_error_message("ResourceNotFound", "Layer unknown", 404); - } - - Layer* layer = serv->get_server_configuration()->get_layer(str_layer); - if ( layer == NULL || ! layer->is_tiles_enabled() ) { - throw TilesException::get_error_message("ResourceNotFound", "Layer "+str_layer+" unknown", 404); - } - - if (! Rok4Format::is_raster(layer->get_pyramid()->get_format())) { - throw TilesException::get_error_message("InvalidParameter", "Vector dataset have to be requested without style", 400); - } - - return new MessageDataStream ( json11::Json{ layer->to_json_styles(this) }.dump(), "application/json", 200 ); -} - - -DataStream* TilesService::get_tilesets ( Request* req, Rok4Server* serv, bool is_map_request ) { - - std::string f = req->get_query_param("f"); - if (f != "" && f != "application/json" && f != "json") { - throw TilesException::get_error_message("InvalidParameter", "Format unknown", 400); - } - - // La couche - std::string str_layer = req->path_params.at(0); - if ( contain_chars(str_layer, "\"")) { - BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in TILES layer: " << str_layer ; - throw TilesException::get_error_message("ResourceNotFound", "Layer unknown", 404); - } - - Layer* layer = serv->get_server_configuration()->get_layer(str_layer); - if ( layer == NULL || ! layer->is_tiles_enabled() ) { - throw TilesException::get_error_message("ResourceNotFound", "Layer "+str_layer+" unknown", 404); - } - - bool is_raster_data = Rok4Format::is_raster(layer->get_pyramid()->get_format()); - - Style* style = NULL; - - if (is_map_request) { - // Map tiles request -> pour les pyramides raster - if (! is_raster_data) { - throw TilesException::get_error_message("InvalidParameter", "Vector dataset have to be requested without style", 400); - } - - std::string str_style = req->path_params.at(1); - - // Traitement du style - if ( contain_chars(str_style, "\"")) { - BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in TILES style: " << str_layer ; - throw TilesException::get_error_message("InvalidParameter", "Style unknown", 400); - } - - style = layer->get_style_by_identifier(str_style); - - if (style == NULL) { - throw TilesException::get_error_message("InvalidParameter", "Style " + str_style + " unknown", 400); - } - - } else { - // Tiles request -> pour les pyramides vecteur - if (is_raster_data) { - throw TilesException::get_error_message("InvalidParameter", "Raster dataset have to be requested with style", 400); - } - } - - return new MessageDataStream ( json11::Json{ layer->to_json_tilesets(this, style) }.dump(), "application/json", 200 ); -} - - -DataStream* TilesService::get_tileset ( Request* req, Rok4Server* serv, bool is_map_request ) { - - std::string f = req->get_query_param("f"); - if (f != "" && f != "application/json" && f != "json") { - throw TilesException::get_error_message("InvalidParameter", "Format unknown", 400); - } - - // La couche - std::string str_layer = req->path_params.at(0); - if ( contain_chars(str_layer, "\"")) { - BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in TILES layer: " << str_layer ; - throw TilesException::get_error_message("ResourceNotFound", "Layer unknown", 404); - } - - Layer* layer = serv->get_server_configuration()->get_layer(str_layer); - if ( layer == NULL || ! layer->is_tiles_enabled() ) { - throw TilesException::get_error_message("ResourceNotFound", "Layer "+str_layer+" unknown", 404); - } - - bool is_raster_data = Rok4Format::is_raster(layer->get_pyramid()->get_format()); - - std::string str_tms; - Style* style = NULL; - - if (is_map_request) { - // Map tiles request -> pour les pyramides raster - if (! is_raster_data) { - throw TilesException::get_error_message("InvalidParameter", "Vector dataset have to be requested without style", 400); - } - - str_tms = req->path_params.at(2); - - std::string str_style = req->path_params.at(1); - - // Traitement du style - if ( contain_chars(str_style, "\"")) { - BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in TILES style: " << str_layer ; - throw TilesException::get_error_message("InvalidParameter", "Style unknown", 400); - } - - style = layer->get_style_by_identifier(str_style); - - if (style == NULL) { - throw TilesException::get_error_message("InvalidParameter", "Style " + str_style + " unknown", 400); - } - - } else { - // Tiles request -> pour les pyramides vecteur - if (is_raster_data) { - throw TilesException::get_error_message("InvalidParameter", "Raster dataset have to be requested with style", 400); - } - - str_tms = req->path_params.at(1); - } - - // Le tile matrix set - if (contain_chars(str_tms, "\"")) { - BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in TILES tile matrix set: " << str_tms; - throw TilesException::get_error_message("InvalidParameter", "Tile matrix set unknown", 400); - } - - TileMatrixSetInfos* tmsi = layer->get_tilematrixset(str_tms); - if (tmsi == NULL || (! reprojection && tmsi->tms->get_id() != layer->get_pyramid()->get_tms()->get_id())) { - throw TilesException::get_error_message("InvalidParameter", "Tile matrix set " + str_tms + " unknown", 400); - } - - return new MessageDataStream ( json11::Json{ layer->to_json_tileset(this, style, tmsi) }.dump(), "application/json", 200 ); -} \ No newline at end of file diff --git a/src/services/tiles/getfeatureinfo.cpp b/src/services/tiles/getfeatureinfo.cpp deleted file mode 100644 index 5b63a37..0000000 --- a/src/services/tiles/getfeatureinfo.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright © (2011-2013) Institut national de l'information - * géographique et forestière - * - * Géoportail SAV - * - * This software is a computer program whose purpose is to publish geographic - * data using OGC WMS and WMTS protocol. - * - * This software is governed by the CeCILL-C license under French law and - * abiding by the rules of distribution of free software. You can use, - * modify and/ or redistribute the software under the terms of the CeCILL-C - * license as circulated by CEA, CNRS and INRIA at the following URL - * "http://www.cecill.info". - * - * As a counterpart to the access to the source code and rights to copy, - * modify and redistribute granted by the license, users are provided only - * with a limited warranty and the software's author, the holder of the - * economic rights, and the successive licensors have only limited - * liability. - * - * In this respect, the user's attention is drawn to the risks associated - * with loading, using, modifying and/or developing or reproducing the - * software by the user in light of its specific status of free software, - * that may mean that it is complicated to manipulate, and that also - * therefore means that it is reserved for developers and experienced - * professionals having in-depth computer knowledge. Users are therefore - * encouraged to load and test the software's suitability as regards their - * requirements in conditions enabling the security of their systems and/or - * data to be ensured and, more generally, to use and operate it in the - * same conditions as regards security. - * - * The fact that you are presently reading this means that you have had - * - * knowledge of the CeCILL-C license and that you accept its terms. - */ - -/** - * \file services/tiles/getfeatureinfo.cpp - ** \~french - * \brief Implémentation de la classe TilesService - ** \~english - * \brief Implements classe TilesService - */ - -#include - -#include "services/tiles/Exception.h" -#include "services/tiles/Service.h" -#include "Rok4Server.h" - -DataStream* TilesService::get_feature_info ( Request* req, Rok4Server* serv ) { - - throw TilesException::get_error_message("NotImplemented", "Coming soon !", 501); -} \ No newline at end of file diff --git a/src/services/tiles/gettile.cpp b/src/services/tiles/gettile.cpp deleted file mode 100644 index 47df9c5..0000000 --- a/src/services/tiles/gettile.cpp +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright © (2011-2013) Institut national de l'information - * géographique et forestière - * - * Géoportail SAV - * - * This software is a computer program whose purpose is to publish geographic - * data using OGC WMS and WMTS protocol. - * - * This software is governed by the CeCILL-C license under French law and - * abiding by the rules of distribution of free software. You can use, - * modify and/ or redistribute the software under the terms of the CeCILL-C - * license as circulated by CEA, CNRS and INRIA at the following URL - * "http://www.cecill.info". - * - * As a counterpart to the access to the source code and rights to copy, - * modify and redistribute granted by the license, users are provided only - * with a limited warranty and the software's author, the holder of the - * economic rights, and the successive licensors have only limited - * liability. - * - * In this respect, the user's attention is drawn to the risks associated - * with loading, using, modifying and/or developing or reproducing the - * software by the user in light of its specific status of free software, - * that may mean that it is complicated to manipulate, and that also - * therefore means that it is reserved for developers and experienced - * professionals having in-depth computer knowledge. Users are therefore - * encouraged to load and test the software's suitability as regards their - * requirements in conditions enabling the security of their systems and/or - * data to be ensured and, more generally, to use and operate it in the - * same conditions as regards security. - * - * The fact that you are presently reading this means that you have had - * - * knowledge of the CeCILL-C license and that you accept its terms. - */ - -/** - * \file services/tiles/gettile.cpp - ** \~french - * \brief Implémentation de la classe TilesService - ** \~english - * \brief Implements classe TilesService - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "services/tiles/Exception.h" -#include "services/tiles/Service.h" -#include "Rok4Server.h" - -DataStream* TilesService::get_tile ( Request* req, Rok4Server* serv, bool is_map_request ) { - - // La couche - std::string str_layer = req->path_params.at(0); - if ( contain_chars(str_layer, "\"")) { - BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in TILES layer: " << str_layer ; - throw TilesException::get_error_message("ResourceNotFound", "Layer unknown", 404); - } - - Layer* layer = serv->get_server_configuration()->get_layer(str_layer); - if ( layer == NULL || ! layer->is_tiles_enabled() ) { - throw TilesException::get_error_message("ResourceNotFound", "Layer "+str_layer+" unknown", 404); - } - - bool is_raster_data = Rok4Format::is_raster(layer->get_pyramid()->get_format()); - - // Le format : mvt, png, jpg ou tiff si fourni - // Le format doit correspondre à celui natif des données - - std::string format; - - if (! req->has_query_param("f")) { - format = Rok4Format::to_tiles_format(layer->get_pyramid()->get_format()); - } else { - format = req->get_query_param("f"); - - if (contain_chars(format, "\"")) { - BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in TILES format: " << format ; - throw TilesException::get_error_message("InvalidParameter", "Format unknown", 400); - } - - if (format != Rok4Format::to_tiles_format(layer->get_pyramid()->get_format())) { - throw TilesException::get_error_message("InvalidParameter", "Format " + format + " unknown", 400); - } - } - - - // Récupération des paramètre selon le type de route (raster ou vecteur) - - std::string str_tms; - std::string str_tm; - std::string str_row; - std::string str_column; - - Style* style = NULL; - - if (is_map_request) { - // Map tiles request -> pour les pyramides raster - if (! is_raster_data) { - throw TilesException::get_error_message("InvalidParameter", "Vector dataset have to be requested with tiles request", 400); - } - - std::string str_style = req->path_params.at(1); - str_tms = req->path_params.at(2); - str_tm = req->path_params.at(3); - str_row = req->path_params.at(4); - str_column = req->path_params.at(5); - - // Traitement du style - if ( contain_chars(str_style, "\"")) { - BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in TILES style: " << str_layer ; - throw TilesException::get_error_message("InvalidParameter", "Style unknown", 400); - } - - style = layer->get_style_by_identifier(str_style); - - if (style == NULL) { - throw TilesException::get_error_message("InvalidParameter", "Style " + str_style + " unknown", 400); - } - - } else { - // Tiles request -> pour les pyramides vecteur - if (is_raster_data) { - throw TilesException::get_error_message("InvalidParameter", "Raster dataset have to be requested with map tiles request", 400); - } - - str_tms = req->path_params.at(1); - str_tm = req->path_params.at(2); - str_row = req->path_params.at(3); - str_column = req->path_params.at(4); - } - - // Le tile matrix set - if (contain_chars(str_tms, "\"")) { - BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in TILES tile matrix set: " << str_tms; - throw TilesException::get_error_message("InvalidParameter", "Tile matrix set unknown", 400); - } - - TileMatrixSetInfos* tmsi = layer->get_tilematrixset(str_tms); - if (tmsi == NULL) { - throw TilesException::get_error_message("InvalidParameter", "Tile matrix set " + str_tms + " unknown", 400); - } - - // Le niveau - if (contain_chars(str_tm, "\"")) { - BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in TILES tile matrix: " << str_tm; - throw TilesException::get_error_message("InvalidParameter", "Tile matrix unknown", 400); - } - - TileMatrix* tm = tmsi->tms->get_tm(str_tm); - if (tm == NULL) { - throw TilesException::get_error_message("InvalidParameter", "Tile matrix " + str_tm + " unknown", 400); - } - - // La colonne - int column; - if (sscanf(str_column.c_str(), "%d", &column) != 1) { - throw TilesException::get_error_message("InvalidParameter", "Invalid column value", 400); - } - - // La ligne - int row; - if (sscanf(str_row.c_str(), "%d", &row) != 1) { - throw TilesException::get_error_message("InvalidParameter", "Invalid row value", 400); - } - - TileMatrixLimits* tml = layer->get_tilematrix_limits(tmsi->tms, tm); - if (tml == NULL) { - // On est hors niveau -> erreur - throw TilesException::get_error_message("ResourceNotFound", "Level out of limits", 404); - } - if (!tml->contain_tile(column, row)) { - // On est hors tuiles -> erreur - throw TilesException::get_error_message("ResourceNotFound", "Tile's indices out of limits", 404); - } - - - // Traitement de la requête - - if (tmsi->tms->get_id() == layer->get_pyramid()->get_tms()->get_id()) { - // TMS d'interrogation natif - Level* level = layer->get_pyramid()->get_level(tm->get_id()); - - DataSource* d = level->get_tile(column, row); - if (d == NULL) { - throw TilesException::get_error_message("ResourceNotFound", "Not data found", 404); - } - - if (layer->get_pyramid()->get_channels() == 1 && format == "png" && style->get_palette() && ! style->get_palette()->is_empty()) { - return new DataStreamFromDataSource(new PaletteDataSource(d, style->get_palette())); - } else { - return new DataStreamFromDataSource(d); - } - } else if (reprojection) { - // TMS d'interrogation à la demande - - BoundingBox bbox = tm->tile_indices_to_bbox(column, row); - int height = tm->get_tile_height(); - int width = tm->get_tile_width(); - CRS* crs = tmsi->tms->get_crs(); - bbox.crs = crs->get_request_code(); - - bool crs_equals = serv->get_services_configuration()->are_crs_equals(layer->get_pyramid()->get_tms()->get_crs()->get_proj_code(), crs->get_proj_code()); - - // On se donne maxium 3 tuiles sur 3 dans la pyramide source pour calculer cette tuile - Image* image = layer->get_pyramid()->getbbox(3, 3, bbox, width, height, crs, crs_equals, layer->get_resampling(), 0); - - if (image == NULL) { - BOOST_LOG_TRIVIAL(warning) << "Cannot process the tile in a non native TMS"; - throw TilesException::get_error_message("ResourceNotFound", "Not data found", 404); - } - - image->set_bbox(bbox); - image->set_crs(crs); - - if (format == "png") { - return new PNGEncoder(image, style->get_palette()); - } - else if (format == "tiff") { - bool is_geotiff = true; - - // Dans le cas d'un geotiff, on renseigne la valeur de nodata - // on ne peut mettre qu'une valeur, ce sera celle du premier canal - int nodata = *(layer->get_pyramid()->get_nodata_value()); - - // La donnée ne peut être retournée que dans le format de la pyramide source utilisée - - switch (layer->get_pyramid()->get_format()) { - case Rok4Format::TIFF_RAW_UINT8: - return new TiffRawEncoder(image, is_geotiff, nodata); - case Rok4Format::TIFF_LZW_UINT8: - return new TiffLZWEncoder(image, is_geotiff, nodata); - case Rok4Format::TIFF_ZIP_UINT8: - return new TiffDeflateEncoder(image, is_geotiff, nodata); - case Rok4Format::TIFF_PKB_UINT8: - return new TiffPackBitsEncoder(image, is_geotiff, nodata); - case Rok4Format::TIFF_RAW_FLOAT32: - return new TiffRawEncoder(image, is_geotiff, nodata); - case Rok4Format::TIFF_LZW_FLOAT32: - return new TiffLZWEncoder(image, is_geotiff, nodata); - case Rok4Format::TIFF_ZIP_FLOAT32: - return new TiffDeflateEncoder(image, is_geotiff, nodata); - case Rok4Format::TIFF_PKB_FLOAT32: - return new TiffPackBitsEncoder(image, is_geotiff, nodata); - default: - delete image; - throw TilesException::get_error_message("ResourceNotFound", "Not data found", 404); - } - } - else if (format == "jpg") { - if (layer->get_pyramid()->get_format() == Rok4Format::TIFF_JPG_UINT8) { - return new JPEGEncoder(image, 75); - } - else if (layer->get_pyramid()->get_format() == Rok4Format::TIFF_JPG90_UINT8) { - return new JPEGEncoder(image, 90); - } - } - } else { - // TMS d'interrogation à la demande mais reprojection non activée - throw TilesException::get_error_message("InvalidParameter", "Tile matrix set " + str_tms + " unknown", 400); - } - - BOOST_LOG_TRIVIAL(error) << "On ne devrait pas passer par là"; - BOOST_LOG_TRIVIAL(error) << req->to_string(); - throw TilesException::get_error_message("ResourceNotFound", "Not data found", 404); -} \ No newline at end of file diff --git a/src/services/tms/Exception.h b/src/services/tms/Exception.h index adc7a4c..22c06e9 100644 --- a/src/services/tms/Exception.h +++ b/src/services/tms/Exception.h @@ -46,9 +46,9 @@ #pragma once #include -#include "boost/format.hpp" +#include -#include "DataStreams.h" +#include "core/DataStreams.h" /** * \author Institut national de l'information géographique et forestière diff --git a/src/services/tms/Service.cpp b/src/services/tms/Service.cpp index 8d9970e..3c98de7 100644 --- a/src/services/tms/Service.cpp +++ b/src/services/tms/Service.cpp @@ -47,9 +47,9 @@ #include "services/tms/Exception.h" #include "services/tms/Service.h" -#include "Rok4Server.h" +#include "core/Rok4Server.h" -TmsService::TmsService (json11::Json& doc) : Service(doc), metadata(NULL) { +TmsService::TmsService (json11::Json& doc) : Service(doc, "TMS service", "TMS service", "http://localhost/tms", "/tms") { if (! is_ok()) { // Le constructeur du service générique a détecté une erreur, on ajoute simplement le service concerné dans le message @@ -61,88 +61,30 @@ TmsService::TmsService (json11::Json& doc) : Service(doc), metadata(NULL) { // Le service a déjà été mis comme n'étant pas actif return; } - - if (doc["title"].is_string()) { - title = doc["title"].string_value(); - } else if (! doc["title"].is_null()) { - error_message = "TMS service: title have to be a string"; - return; - } else { - title = "TMS service"; - } - - if (doc["abstract"].is_string()) { - abstract = doc["abstract"].string_value(); - } else if (! doc["abstract"].is_null()) { - error_message = "TMS service: abstract have to be a string"; - return; - } else { - abstract = "TMS service"; - } - - if (doc["keywords"].is_array()) { - for (json11::Json kw : doc["keywords"].array_items()) { - if (kw.is_string()) { - keywords.push_back(Keyword ( kw.string_value())); - } else { - error_message = "TMS service: keywords have to be a string array"; - return; - } - } - } else if (! doc["keywords"].is_null()) { - error_message = "TMS service: keywords have to be a string array"; - return; - } - - if (doc["endpoint_uri"].is_string()) { - endpoint_uri = doc["endpoint_uri"].string_value(); - } else if (! doc["endpoint_uri"].is_null()) { - error_message = "TMS service: endpoint_uri have to be a string"; - return; - } else { - endpoint_uri = "http://localhost/tms"; - } - - if (doc["root_path"].is_string()) { - root_path = doc["root_path"].string_value(); - } else if (! doc["root_path"].is_null()) { - error_message = "TMS service: root_path have to be a string"; - return; - } else { - root_path = "/tms"; - } - - if (doc["metadata"].is_object()) { - metadata = new Metadata ( doc["metadata"] ); - if (metadata->get_missing_field() != "") { - error_message = "TMS service: invalid metadata: have to own a field " + metadata->get_missing_field(); - return ; - } - } } -DataStream* TmsService::process_request(Request* req, Rok4Server* serv) { +DataStream* TmsService::process_request(Request* req, ServicesConfiguration* services) { BOOST_LOG_TRIVIAL(debug) << "TMS service"; if ( match_route( "/([^/]+)/?", {"GET"}, req ) ) { BOOST_LOG_TRIVIAL(debug) << "GETCAPABILITIES request"; - return get_capabilities(req, serv); + return get_capabilities(req, services); } else if ( match_route( "/([^/]+)/([^/]+)/?", {"GET"}, req ) ) { BOOST_LOG_TRIVIAL(debug) << "GETTILES request"; - return get_tiles(req, serv); + return get_tiles(req, services); } else if ( match_route( "/([^/]+)/([^/]+)/metadata\\.json", {"GET"}, req ) ) { BOOST_LOG_TRIVIAL(debug) << "GETMETADATA request"; - return get_metadata(req, serv); + return get_metadata(req, services); } else if ( match_route( "/([^/]+)/([^/]+)/gdal\\.xml", {"GET"}, req ) ) { BOOST_LOG_TRIVIAL(debug) << "GETGDAL request"; - return get_gdal(req, serv); + return get_gdal(req, services); } else if ( match_route( "/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)\\.(.*)", {"GET"}, req ) ) { BOOST_LOG_TRIVIAL(debug) << "GETTILE request"; - return get_tile(req, serv); + return get_tile(req, services); } else { throw TmsException::get_error_message("Unknown tms request path", 400); } diff --git a/src/services/tms/Service.h b/src/services/tms/Service.h index 13515b4..bfdad78 100644 --- a/src/services/tms/Service.h +++ b/src/services/tms/Service.h @@ -47,7 +47,6 @@ class TmsService; #pragma once #include "services/Service.h" -#include "configurations/Metadata.h" /** * \author Institut national de l'information géographique et forestière @@ -57,18 +56,16 @@ class TmsService; class TmsService : public Service { private: - DataStream* get_capabilities ( Request* req, Rok4Server* serv ); - DataStream* get_tiles ( Request* req, Rok4Server* serv ); - DataStream* get_metadata ( Request* req, Rok4Server* serv ); - DataStream* get_gdal ( Request* req, Rok4Server* serv ); - DataStream* get_tile ( Request* req, Rok4Server* serv ); - - Metadata* metadata; + DataStream* get_capabilities ( Request* req, ServicesConfiguration* services ); + DataStream* get_tiles ( Request* req, ServicesConfiguration* services ); + DataStream* get_metadata ( Request* req, ServicesConfiguration* services ); + DataStream* get_gdal ( Request* req, ServicesConfiguration* services ); + DataStream* get_tile ( Request* req, ServicesConfiguration* services ); std::string cache_getcapabilities; public: - DataStream* process_request(Request* req, Rok4Server* serv); + DataStream* process_request(Request* req, ServicesConfiguration* services ); /** * \~french @@ -96,9 +93,7 @@ class TmsService : public Service { * \~english * \brief Destructor */ - ~TmsService() { - if (metadata) delete metadata; - }; + ~TmsService() {}; }; diff --git a/src/services/tms/getcapabilities.cpp b/src/services/tms/getcapabilities.cpp index c12488f..21ea6f1 100644 --- a/src/services/tms/getcapabilities.cpp +++ b/src/services/tms/getcapabilities.cpp @@ -56,9 +56,9 @@ using boost::property_tree::xml_writer_settings; #include "services/tms/Exception.h" #include "services/tms/Service.h" -#include "Rok4Server.h" +#include "core/Rok4Server.h" -DataStream* TmsService::get_capabilities ( Request* req, Rok4Server* serv ) { +DataStream* TmsService::get_capabilities ( Request* req, ServicesConfiguration* services ) { if ( req->path_params.at(0) != "1.0.0" ) { throw TmsException::get_error_message("Invalid version (only 1.0.0 available)", 400); @@ -80,7 +80,7 @@ DataStream* TmsService::get_capabilities ( Request* req, Rok4Server* serv ) { root.add("KeywordList", keywords.at(i).get_content() ); } - serv->get_services_configuration()->contact->add_node_tms(root, serv->get_services_configuration()->service_provider); + services->contact->add_node_tms(root, services->service_provider); if (metadata) { metadata->add_node_tms(root); @@ -88,7 +88,7 @@ DataStream* TmsService::get_capabilities ( Request* req, Rok4Server* serv ) { ptree& contents_node = root.add("TileMaps", ""); - std::map::iterator layers_iterator ( serv->get_server_configuration()->get_layers().begin() ), layers_end ( serv->get_server_configuration()->get_layers().end() ); + std::map::iterator layers_iterator ( services->get_layers().begin() ), layers_end ( services->get_layers().end() ); for ( ; layers_iterator != layers_end; ++layers_iterator ) { layers_iterator->second->add_node_tms(contents_node, this); } @@ -101,7 +101,7 @@ DataStream* TmsService::get_capabilities ( Request* req, Rok4Server* serv ) { return new MessageDataStream ( ss.str(), "text/xml", 200 ); } -DataStream* TmsService::get_tiles ( Request* req, Rok4Server* serv ) { +DataStream* TmsService::get_tiles ( Request* req, ServicesConfiguration* services ) { // La version if ( req->path_params.at(0) != "1.0.0" ) @@ -114,7 +114,7 @@ DataStream* TmsService::get_tiles ( Request* req, Rok4Server* serv ) { throw TmsException::get_error_message("Layer unknown", 400); } - Layer* layer = serv->get_server_configuration()->get_layer(str_layer); + Layer* layer = services->get_layer(str_layer); if ( layer == NULL || ! layer->is_tms_enabled() ) { throw TmsException::get_error_message("Layer " +str_layer+" unknown", 400); } @@ -122,7 +122,7 @@ DataStream* TmsService::get_tiles ( Request* req, Rok4Server* serv ) { return new MessageDataStream ( layer->get_description_tms(this), "text/xml", 200 ); } -DataStream* TmsService::get_metadata ( Request* req, Rok4Server* serv ) { +DataStream* TmsService::get_metadata ( Request* req, ServicesConfiguration* services ) { // La version if ( req->path_params.at(0) != "1.0.0" ) @@ -135,7 +135,7 @@ DataStream* TmsService::get_metadata ( Request* req, Rok4Server* serv ) { throw TmsException::get_error_message("Layer unknown", 400); } - Layer* layer = serv->get_server_configuration()->get_layer(str_layer); + Layer* layer = services->get_layer(str_layer); if ( layer == NULL || ! layer->is_tms_enabled() ) { throw TmsException::get_error_message("Layer " +str_layer+" unknown", 400); } @@ -143,7 +143,7 @@ DataStream* TmsService::get_metadata ( Request* req, Rok4Server* serv ) { return new MessageDataStream ( layer->get_description_tilejson(this), "application/json", 200 ); } -DataStream* TmsService::get_gdal ( Request* req, Rok4Server* serv ) { +DataStream* TmsService::get_gdal ( Request* req, ServicesConfiguration* services ) { // La version if ( req->path_params.at(0) != "1.0.0" ) @@ -156,12 +156,12 @@ DataStream* TmsService::get_gdal ( Request* req, Rok4Server* serv ) { throw TmsException::get_error_message("Layer unknown", 400); } - Layer* layer = serv->get_server_configuration()->get_layer(str_layer); + Layer* layer = services->get_layer(str_layer); if ( layer == NULL || ! layer->is_tms_enabled() ) { throw TmsException::get_error_message("Layer " +str_layer+" unknown", 400); } - if (! Rok4Format::is_raster(layer->get_pyramid()->get_format())) { + if (! layer->is_raster()) { throw TmsException::get_error_message("Layer " +str_layer+" is vector data: cannot describe it with this format", 400); } diff --git a/src/services/tms/gettile.cpp b/src/services/tms/gettile.cpp index 632a1ce..2569ad6 100644 --- a/src/services/tms/gettile.cpp +++ b/src/services/tms/gettile.cpp @@ -49,9 +49,10 @@ #include "services/tms/Exception.h" #include "services/tms/Service.h" -#include "Rok4Server.h" +#include "core/Rok4Server.h" +#include "core/Tile.h" -DataStream* TmsService::get_tile ( Request* req, Rok4Server* serv ) { +DataStream* TmsService::get_tile ( Request* req, ServicesConfiguration* services ) { // La version if ( req->path_params.at(0) != "1.0.0" ) @@ -64,7 +65,7 @@ DataStream* TmsService::get_tile ( Request* req, Rok4Server* serv ) { throw TmsException::get_error_message("Layer unknown", 400); } - Layer* layer = serv->get_server_configuration()->get_layer(str_layer); + Layer* layer = services->get_layer(str_layer); if ( layer == NULL || ! layer->is_tms_enabled() ) { throw TmsException::get_error_message("Layer " + str_layer + " unknown", 400); } @@ -111,7 +112,7 @@ DataStream* TmsService::get_tile ( Request* req, Rok4Server* serv ) { // Le style Style* style; - if (Rok4Format::is_raster(layer->get_pyramid()->get_format())) { + if (layer->is_raster()) { style = layer->get_default_style(); } @@ -131,14 +132,10 @@ DataStream* TmsService::get_tile ( Request* req, Rok4Server* serv ) { std::string format = Rok4Format::to_mime_type ( ( layer->get_pyramid()->get_format() ) ); - DataSource* d = layer->get_pyramid()->get_level(tm->get_id())->get_tile(column, row); + // Traitement de la requête + DataStream* d = Tile::get_tile(services, layer, tms, tm, column, row, format, style); if (d == NULL) { throw TmsException::get_error_message("No data found", 404); } - - if (format == "image/png" && style->get_palette() && ! style->get_palette()->is_empty()) { - return new DataStreamFromDataSource(new PaletteDataSource(d, style->get_palette())); - } else { - return new DataStreamFromDataSource(d); - } -} \ No newline at end of file + return d; +} diff --git a/src/services/wms/Exception.h b/src/services/wms/Exception.h index e4be5e9..e0517ab 100644 --- a/src/services/wms/Exception.h +++ b/src/services/wms/Exception.h @@ -46,9 +46,9 @@ #pragma once #include -#include "boost/format.hpp" +#include -#include "DataStreams.h" +#include "core/DataStreams.h" /** * \author Institut national de l'information géographique et forestière diff --git a/src/services/wms/Service.cpp b/src/services/wms/Service.cpp index 13891d4..791ee7d 100644 --- a/src/services/wms/Service.cpp +++ b/src/services/wms/Service.cpp @@ -49,9 +49,9 @@ #include "services/wms/Exception.h" #include "services/wms/Service.h" -#include "Rok4Server.h" +#include "core/Rok4Server.h" -WmsService::WmsService (json11::Json& doc, ServicesConfiguration* svc) : Service(doc), metadata(NULL) { +WmsService::WmsService (json11::Json& doc, ServicesConfiguration* svc) : Service(doc, "WMS service", "WMS service", "http://localhost/wms", "/wms") { if (! is_ok()) { // Le constructeur du service générique a détecté une erreur, on ajoute simplement le service concerné dans le message @@ -73,119 +73,6 @@ WmsService::WmsService (json11::Json& doc, ServicesConfiguration* svc) : Service name = "WMS"; } - if (doc["title"].is_string()) { - title = doc["title"].string_value(); - } else if (! doc["title"].is_null()) { - error_message = "WMS service: title have to be a string"; - return; - } else { - title = "WMS service"; - } - - if (doc["abstract"].is_string()) { - abstract = doc["abstract"].string_value(); - } else if (! doc["abstract"].is_null()) { - error_message = "WMS service: abstract have to be a string"; - return; - } else { - abstract = "WMS service"; - } - - if (doc["keywords"].is_array()) { - for (json11::Json kw : doc["keywords"].array_items()) { - if (kw.is_string()) { - keywords.push_back(Keyword ( kw.string_value())); - } else { - error_message = "WMS service: keywords have to be a string array"; - return; - } - } - } else if (! doc["keywords"].is_null()) { - error_message = "WMS service: keywords have to be a string array"; - return; - } - - if (doc["endpoint_uri"].is_string()) { - endpoint_uri = doc["endpoint_uri"].string_value(); - } else if (! doc["endpoint_uri"].is_null()) { - error_message = "WMS service: endpoint_uri have to be a string"; - return; - } else { - endpoint_uri = "http://localhost/wms"; - } - - if (doc["root_path"].is_string()) { - root_path = doc["root_path"].string_value(); - } else if (! doc["root_path"].is_null()) { - error_message = "WMS service: root_path have to be a string"; - return; - } else { - root_path = "/wms"; - } - - if (doc["metadata"].is_object()) { - metadata = new Metadata ( doc["metadata"] ); - if (metadata->get_missing_field() != "") { - error_message = "WMS service: invalid metadata: have to own a field " + metadata->get_missing_field(); - return ; - } - } - - if (doc["reprojection"].is_bool()) { - reprojection = doc["reprojection"].bool_value(); - } else if (! doc["reprojection"].is_null()) { - error_message = "WMS service: reprojection have to be a boolean"; - return; - } else { - reprojection = false; - } - - if (doc["inspire"].is_bool()) { - default_inspire = doc["inspire"].bool_value(); - } else if (! doc["inspire"].is_null()) { - error_message = "WMS service: inspire have to be a boolean"; - return; - } else { - default_inspire = false; - } - - if (doc["formats"].is_array()) { - for (json11::Json f : doc["formats"].array_items()) { - if (f.is_string()) { - std::string format = f.string_value(); - if ( format != "image/jpeg" && - format != "image/png" && - format != "image/tiff" && - format != "image/geotiff" && - format != "image/x-bil;bits=32" && - format != "image/gif" && - format != "text/asc" ) { - error_message = "WMS service: format [" + format + "] is not an handled MIME format"; - return; - } else { - formats.push_back ( format ); - } - } else { - error_message = "WMS service: formats have to be a string array"; - return; - } - } - } else if (! doc["formats"].is_null()) { - error_message = "WMS service: formats have to be a string array"; - return; - } else { - formats.push_back("image/jpeg"); - formats.push_back("image/png"); - formats.push_back("image/tiff"); - formats.push_back("image/geotiff"); - formats.push_back("image/x-bil;bits=32"); - } - - info_formats.push_back("text/plain"); - info_formats.push_back("text/xml"); - info_formats.push_back("text/html"); - info_formats.push_back("application/json"); - if (doc["root_layer"].is_object()) { if (doc["root_layer"]["title"].is_string()) { root_layer_title = doc["root_layer"]["title"].string_value(); @@ -212,144 +99,10 @@ WmsService::WmsService (json11::Json& doc, ServicesConfiguration* svc) : Service root_layer_abstract = "WMS layers"; } - if (doc["limits"].is_object()) { - if (doc["limits"]["layers_count"].is_number() && doc["limits"]["layers_count"].number_value() >= 1) { - max_layers_count = doc["limits"]["layers_count"].number_value(); - } else if (! doc["limits"]["layers_count"].is_null()) { - error_message = "WMS service: limits.layers_count have to be an integer >= 1"; - return; - } else { - max_layers_count = 1; - } - - if (doc["limits"]["width"].is_number() && doc["limits"]["width"].number_value() >= 1) { - max_width = doc["limits"]["width"].number_value(); - } else if (! doc["limits"]["width"].is_null()) { - error_message = "WMS service: limits.width have to be an integer >= 1"; - return; - } else { - max_width = 5000; - } - - if (doc["limits"]["height"].is_number() && doc["limits"]["height"].number_value() >= 1) { - max_height = doc["limits"]["height"].number_value(); - } else if (! doc["limits"]["height"].is_null()) { - error_message = "WMS service: limits.height have to be an integer >= 1"; - return; - } else { - max_height = 5000; - } - - if (doc["limits"]["tile_x"].is_number() && doc["limits"]["tile_x"].number_value() >= 1) { - max_tile_x = doc["limits"]["tile_x"].number_value(); - } else if (! doc["limits"]["tile_x"].is_null()) { - error_message = "WMS service: limits.tile_x have to be an integer >= 1"; - return; - } else { - max_tile_x = 32; - } - - if (doc["limits"]["tile_y"].is_number() && doc["limits"]["tile_y"].number_value() >= 1) { - max_tile_y = doc["limits"]["tile_y"].number_value(); - } else if (! doc["limits"]["tile_y"].is_null()) { - error_message = "WMS service: limits.tile_y have to be an integer >= 1"; - return; - } else { - max_tile_y = 32; - } - - } else if (! doc["limits"].is_null()) { - error_message = "WMS service: limits have to be an object"; - return; - } else { - max_layers_count = 1; - max_width = 5000; - max_height = 5000; - max_tile_x = 32; - max_tile_y = 32; - } - - bool crs84_present = false; - if (reprojection && doc["crs"].is_array()) { - for (json11::Json c : doc["crs"].array_items()) { - if (c.is_string()) { - std::string crs_string = c.string_value(); - - CRS* crs = CrsBook::get_crs( crs_string ); - if ( ! crs->is_define() ) { - BOOST_LOG_TRIVIAL(warning) << "The (WMS) CRS [" << crs_string <<"] is not present in PROJ" ; - continue; - } - - BOOST_LOG_TRIVIAL(info) << "Adding global CRS " << crs->get_request_code() ; - crss.push_back(crs); - if (crs->get_request_code() == "CRS:84") { - crs84_present = true; - } - - if (svc->handle_crs_equivalences()) { - std::vector eqs = svc->get_equals_crs(crs->get_request_code()); - size_t init_size = crss.size(); - for (unsigned int e = 0; e < eqs.size(); e++) { - bool already_in = false; - for ( int i = 0; i < init_size ; i++ ) { - if (crss.at( i )->cmp_request_code(eqs.at(e)->get_request_code() ) ){ - already_in = true; - break; - } - } - if (! already_in) { - BOOST_LOG_TRIVIAL(info) << "Adding equivalent global CRS [" << eqs.at(e)->get_request_code() <<"] of [" << crs->get_request_code() << "]" ; - crss.push_back(eqs.at(e)); - if (eqs.at(e)->get_request_code() == "CRS:84") { - crs84_present = true; - } - } - } - } - } else { - error_message = "WMS service: crs have to be a string array"; - return; - } - } - } else if (! doc["crs"].is_null()) { - error_message = "WMS service: crs have to be a string array with enabled reprojection"; - return; - } - - if (! crs84_present) { - BOOST_LOG_TRIVIAL(info) << "CRS:84 not found -> adding global CRS CRS:84" ; - CRS* crs = CrsBook::get_crs( "CRS:84" ); - - if ( ! crs->is_define() ) { - error_message = "WMS service: The CRS [CRS:84] is not present in PROJ" ; - return; - } - - crss.push_back ( crs ); - - if (svc->handle_crs_equivalences()) { - std::vector eqs = svc->get_equals_crs(crs->get_request_code()); - size_t init_size = crss.size(); - for (unsigned int e = 0; e < eqs.size(); e++) { - bool already_in = false; - for ( int i = 0; i < init_size ; i++ ) { - if (crss.at( i )->cmp_request_code(eqs.at(e)->get_request_code() ) ){ - already_in = true; - } - } - if (! already_in) { - BOOST_LOG_TRIVIAL(info) << "Adding equivalent global CRS [" << eqs.at(e)->get_request_code() <<"] of [CRS:84]" ; - crss.push_back(eqs.at(e)); - } - } - } - } - } -DataStream* WmsService::process_request(Request* req, Rok4Server* serv) { +DataStream* WmsService::process_request(Request* req, ServicesConfiguration* services) { BOOST_LOG_TRIVIAL(debug) << "WMS service"; // On contrôle le service précisé en paramètre de requête @@ -376,42 +129,15 @@ DataStream* WmsService::process_request(Request* req, Rok4Server* serv) { if (param_request == "getcapabilities") { BOOST_LOG_TRIVIAL(debug) << "GETCAPABILITIES request"; - return get_capabilities(req, serv); + return get_capabilities(req, services); } else if (param_request == "getfeatureinfo") { BOOST_LOG_TRIVIAL(debug) << "GETFEATUREINFO request"; - return get_feature_info(req, serv); + return get_feature_info(req, services); } else if (param_request == "getmap") { BOOST_LOG_TRIVIAL(debug) << "GETMAP request"; - return get_map(req, serv); + return get_map(req, services); } else { throw WmsException::get_error_message("REQUEST query parameter unknown", "OperationNotSupported", 400); } }; - -bool WmsService::is_available_crs(CRS* c) { - return is_available_crs(c->get_request_code()); -} -bool WmsService::is_available_crs(std::string c) { - if (! reprojection) { - return false; - } - for ( unsigned int k = 0; k < crss.size(); k++ ) { - if ( crss.at (k)->cmp_request_code ( c ) ) { - return true; - } - } - return false; -} - -bool WmsService::is_available_format(std::string f) { - return (std::find(formats.begin(), formats.end(), f) != formats.end()); -} - -bool WmsService::is_available_infoformat(std::string f) { - return (std::find(info_formats.begin(), info_formats.end(), f) != info_formats.end()); -} - -std::vector* WmsService::get_available_crs() { - return &crss; -} \ No newline at end of file diff --git a/src/services/wms/Service.h b/src/services/wms/Service.h index fd3bde9..f53b71d 100644 --- a/src/services/wms/Service.h +++ b/src/services/wms/Service.h @@ -48,7 +48,6 @@ class WmsService; #pragma once #include "services/Service.h" -#include "configurations/Metadata.h" #include "configurations/Services.h" /** @@ -59,34 +58,20 @@ class WmsService; class WmsService : public Service { private: - DataStream* get_capabilities ( Request* req, Rok4Server* serv ); - DataStream* get_feature_info ( Request* req, Rok4Server* serv ); - DataStream* get_map ( Request* req, Rok4Server* serv ); + DataStream* get_capabilities ( Request* req, ServicesConfiguration* services ); + DataStream* get_feature_info ( Request* req, ServicesConfiguration* services ); + DataStream* get_map ( Request* req, ServicesConfiguration* services ); std::string name; - Metadata* metadata; - bool reprojection; - std::vector info_formats; - std::vector formats; std::string root_layer_title; std::string root_layer_abstract; - int max_layers_count; - int max_width; - int max_height; - int max_tile_x; - int max_tile_y; - - std::vector crss; - - bool default_inspire; - std::string cache_getcapabilities; std::string cache_getcapabilities_inspire; public: - DataStream* process_request(Request* req, Rok4Server* serv); + DataStream* process_request(Request* req, ServicesConfiguration* services ); /** * \~french @@ -115,63 +100,7 @@ class WmsService : public Service { * \~english * \brief Destructor */ - ~WmsService() { - if (metadata) delete metadata; - }; - - /** - * \~french - * \brief Teste la présence du CRS dans la liste - * \return Présent ou non - * \~english - * \brief Test if CRS is in the CRS list - * \return Present or not - */ - bool is_available_crs(CRS* c) ; - - /** - * \~french - * \brief Teste la présence du CRS dans la liste - * \return Présent ou non - * \~english - * \brief Test if CRS is in the CRS list - * \return Present or not - */ - bool is_available_crs(std::string c) ; - - /** - * \~french - * \brief Teste la validité du format - * \~english - * \brief Test if format is valid - */ - bool is_available_format(std::string f) ; - - /** - * \~french - * \brief Liste des CRS globaux du service - * \~english - * \brief Global service CRS list - */ - std::vector* get_available_crs() ; - - /** - * \~french - * \brief Teste la validité du info format - * \~english - * \brief Test if info format is valid - */ - bool is_available_infoformat(std::string f) ; - - /** - * \~french - * \brief La reprojection est-elle activée - * \~english - * \brief Is reprojection enabled - */ - bool reprojection_enabled() { - return reprojection; - }; + ~WmsService() {}; }; diff --git a/src/services/wms/getcapabilities.cpp b/src/services/wms/getcapabilities.cpp index c27dd95..0b3373c 100644 --- a/src/services/wms/getcapabilities.cpp +++ b/src/services/wms/getcapabilities.cpp @@ -54,9 +54,11 @@ using boost::property_tree::xml_writer_settings; #include "services/wms/Exception.h" #include "services/wms/Service.h" -#include "Rok4Server.h" +#include "core/Rok4Server.h" -DataStream* WmsService::get_capabilities ( Request* req, Rok4Server* serv ) { +DataStream* WmsService::get_capabilities ( Request* req, ServicesConfiguration* services ) { + + bool default_inspire = services->default_inspire; if ( req->is_inspire(default_inspire) && ! cache_getcapabilities_inspire.empty()) { return new MessageDataStream ( cache_getcapabilities_inspire, "text/xml", 200 ); @@ -65,8 +67,6 @@ DataStream* WmsService::get_capabilities ( Request* req, Rok4Server* serv ) { return new MessageDataStream ( cache_getcapabilities, "text/xml", 200 ); } - ServicesConfiguration* services = serv->get_services_configuration(); - ptree tree; ptree& root = tree.add("WMS_Capabilities", ""); @@ -101,9 +101,9 @@ DataStream* WmsService::get_capabilities ( Request* req, Rok4Server* serv ) { service_node.add("Fees", services->fee); service_node.add("AccessConstraints", services->access_constraint); - service_node.add("LayerLimit", max_layers_count); - service_node.add("MaxWidth", max_width); - service_node.add("MaxHeight", max_height); + service_node.add("LayerLimit", services->map_max_layers_count); + service_node.add("MaxWidth", services->map_max_width); + service_node.add("MaxHeight", services->map_max_height); ptree& capability_node = root.add("Capability", ""); @@ -119,16 +119,16 @@ DataStream* WmsService::get_capabilities ( Request* req, Rok4Server* serv ) { op_getcapabilities.add("DCPType.HTTP.Get.OnlineResource..xlink:type", "simple"); ptree& op_getmap = capability_node.add("Request.GetMap", ""); - for ( unsigned int i = 0; i < formats.size(); i++ ) { - op_getmap.add("Format", formats.at(i)); + for ( unsigned int i = 0; i < services->map_formats.size(); i++ ) { + op_getmap.add("Format", services->map_formats.at(i)); } op_getmap.add("DCPType.HTTP.Get.OnlineResource..xlink:href", endpoint_uri + additionnal_params); op_getmap.add("DCPType.HTTP.Get.OnlineResource..xmlns:xlink", "http://www.w3.org/1999/xlink"); op_getmap.add("DCPType.HTTP.Get.OnlineResource..xlink:type", "simple"); ptree& op_getfeatureinfo = capability_node.add("Request.GetFeatureInfo", ""); - for ( unsigned int i = 0; i < info_formats.size(); i++ ) { - op_getfeatureinfo.add("Format", info_formats.at(i)); + for ( unsigned int i = 0; i < services->info_formats.size(); i++ ) { + op_getfeatureinfo.add("Format", services->info_formats.at(i)); } op_getfeatureinfo.add("DCPType.HTTP.Get.OnlineResource..xlink:href", endpoint_uri + additionnal_params); op_getfeatureinfo.add("DCPType.HTTP.Get.OnlineResource..xmlns:xlink", "http://www.w3.org/1999/xlink"); @@ -153,8 +153,8 @@ DataStream* WmsService::get_capabilities ( Request* req, Rok4Server* serv ) { contents_node.add("Title", root_layer_title); contents_node.add("Abstract", root_layer_abstract); - for ( unsigned int i = 0; i < crss.size(); i++ ) { - contents_node.add("CRS", crss.at(i)->get_request_code()); + for ( unsigned int i = 0; i < services->map_crss.size(); i++ ) { + contents_node.add("CRS", services->map_crss.at(i)->get_request_code()); } BoundingBox gbbox ( -180.0,-90.0,180.0,90.0 ); @@ -162,7 +162,7 @@ DataStream* WmsService::get_capabilities ( Request* req, Rok4Server* serv ) { gbbox.crs = "CRS:84"; gbbox.add_node(contents_node, false, false); - std::map::iterator layers_iterator ( serv->get_server_configuration()->get_layers().begin() ), layers_end ( serv->get_server_configuration()->get_layers().end() ); + std::map::iterator layers_iterator ( services->get_layers().begin() ), layers_end ( services->get_layers().end() ); for ( ; layers_iterator != layers_end; ++layers_iterator ) { layers_iterator->second->add_node_wms(contents_node, this, req->is_inspire(default_inspire)); } diff --git a/src/services/wms/getfeatureinfo.cpp b/src/services/wms/getfeatureinfo.cpp index e071954..03a5467 100644 --- a/src/services/wms/getfeatureinfo.cpp +++ b/src/services/wms/getfeatureinfo.cpp @@ -48,9 +48,10 @@ #include "services/wms/Exception.h" #include "services/wms/Service.h" -#include "Rok4Server.h" +#include "core/Rok4Server.h" +#include "core/Map.h" -DataStream* WmsService::get_feature_info ( Request* req, Rok4Server* serv ) { +DataStream* WmsService::get_feature_info ( Request* req, ServicesConfiguration* services ) { // Les couches std::vector layers; @@ -61,8 +62,8 @@ DataStream* WmsService::get_feature_info ( Request* req, Rok4Server* serv ) { std::vector vector_layers; boost::split(vector_layers, str_layers, boost::is_any_of(",")); - if ( vector_layers.size() > max_layers_count ) { - throw WmsException::get_error_message("Number of layers exceed the limit (" + std::to_string(max_layers_count) + ")", "InvalidParameterValue", 400); + if ( vector_layers.size() > services->map_max_layers_count ) { + throw WmsException::get_error_message("Number of layers exceed the limit (" + std::to_string(services->map_max_layers_count) + ")", "InvalidParameterValue", 400); } for (unsigned int i = 0 ; i < vector_layers.size(); i++ ) { @@ -72,7 +73,7 @@ DataStream* WmsService::get_feature_info ( Request* req, Rok4Server* serv ) { throw WmsException::get_error_message("Layer unknown", "LayerNotDefined", 400); } - Layer* layer = serv->get_server_configuration()->get_layer(vector_layers.at(i)); + Layer* layer = services->get_layer(vector_layers.at(i)); if (layer == NULL || ! layer->is_wms_enabled()) { throw WmsException::get_error_message("Layer " + vector_layers.at(i) + " unknown", "LayerNotDefined", 400); } @@ -100,7 +101,7 @@ DataStream* WmsService::get_feature_info ( Request* req, Rok4Server* serv ) { throw WmsException::get_error_message("Layer unknown", "LayerNotDefined", 400); } - Layer* layer = serv->get_server_configuration()->get_layer(vector_query_layers.at(i)); + Layer* layer = services->get_layer(vector_query_layers.at(i)); if (layer == NULL || ! layer->is_wms_enabled()) { throw WmsException::get_error_message("Layer " + vector_query_layers.at(i) + " unknown", "LayerNotDefined", 400); } @@ -126,8 +127,8 @@ DataStream* WmsService::get_feature_info ( Request* req, Rok4Server* serv ) { if ( width <= 0 ) throw WmsException::get_error_message("WIDTH query parameter have to be a strictly positive integer", "InvalidParameterValue", 400); - if ( width > max_width ) - throw WmsException::get_error_message("WIDTH query parameter exceed the limit (" + std::to_string(max_width) + ")", "InvalidParameterValue", 400); + if ( width > services->map_max_width ) + throw WmsException::get_error_message("WIDTH query parameter exceed the limit (" + std::to_string(services->map_max_width) + ")", "InvalidParameterValue", 400); // La hauteur int height; @@ -138,8 +139,8 @@ DataStream* WmsService::get_feature_info ( Request* req, Rok4Server* serv ) { if ( height <= 0 ) throw WmsException::get_error_message("HEIGHT query parameter have to be a strictly positive integer", "InvalidParameterValue", 400); - if ( height > max_height ) - throw WmsException::get_error_message("HEIGHT query parameter exceed the limit (" + std::to_string(max_width) + ")", "InvalidParameterValue", 400); + if ( height > services->map_max_height ) + throw WmsException::get_error_message("HEIGHT query parameter exceed the limit (" + std::to_string(services->map_max_height) + ")", "InvalidParameterValue", 400); // le CRS CRS* crs; @@ -156,9 +157,9 @@ DataStream* WmsService::get_feature_info ( Request* req, Rok4Server* serv ) { throw WmsException::get_error_message("CRS " + str_crs + " unknown", "InvalidParameterValue", 400); } - if (! is_available_crs(str_crs) ) { + if (! services->is_map_available_crs(str_crs) ) { for ( unsigned int i = 0; i < layers.size() ; i++ ) { - bool crs_equals = serv->get_services_configuration()->are_crs_equals(crs->get_request_code(), layers.at(i)->get_pyramid()->get_tms()->get_crs()->get_request_code()); + bool crs_equals = services->are_crs_equals(crs->get_request_code(), layers.at(i)->get_pyramid()->get_tms()->get_crs()->get_request_code()); if (! crs_equals && ! layers.at ( i )->is_available_crs(str_crs) ) throw WmsException::get_error_message("CRS is not available for the layer " + layers.at ( i )->get_id(), "InvalidParameterValue", 400); } @@ -174,7 +175,7 @@ DataStream* WmsService::get_feature_info ( Request* req, Rok4Server* serv ) { throw WmsException::get_error_message("Format unknown", "InvalidParameterValue", 400); } - if (! is_available_format(format)) throw WmsException::get_error_message("Format " + format + " unknown", "InvalidParameterValue", 400); + if (! services->is_map_available_format(format)) throw WmsException::get_error_message("Format " + format + " unknown", "InvalidParameterValue", 400); // La bbox std::string str_bbox = req->get_query_param("bbox"); @@ -279,7 +280,7 @@ DataStream* WmsService::get_feature_info ( Request* req, Rok4Server* serv ) { throw WmsException::get_error_message("InfoFormat unknown", "InvalidParameterValue", 400); } - if ( ! is_available_infoformat(info_format) ) + if ( ! services->is_available_infoformat(info_format) ) throw WmsException::get_error_message("INFO_FORMAT " + info_format + " unknown", "InvalidParameterValue", 400); // i @@ -324,102 +325,16 @@ DataStream* WmsService::get_feature_info ( Request* req, Rok4Server* serv ) { } // Traitement de la requête - - Layer* layer = query_layers.at(0); - - std::string gfi_type = layer->get_gfi_type(); - if (gfi_type.compare("PYRAMID") == 0) { - - // On cherche la valeur du pixel source sous le clique - bool crs_equals = serv->get_services_configuration()->are_crs_equals(crs->get_request_code(), layer->get_pyramid()->get_tms()->get_crs()->get_request_code()); - - if (! crs_equals && ! reprojection) { - throw WmsException::get_error_message("Reprojection is not available", "InvalidParameterValue", 400); - } - - Image* image = layer->get_pyramid()->getbbox(max_tile_x, max_tile_y, bbox, width, height, crs, crs_equals, layer->get_resampling(), dpi); - - if (image == NULL) { - throw WmsException::get_error_message("BBOX too big", "InvalidParameterValue", 400); - } - - std::vector gfi_data; - int bands = image->get_channels(); - switch (layer->get_pyramid()->get_format()) { - case Rok4Format::TIFF_RAW_UINT8: - case Rok4Format::TIFF_JPG_UINT8: - case Rok4Format::TIFF_PNG_UINT8: - case Rok4Format::TIFF_LZW_UINT8: - case Rok4Format::TIFF_ZIP_UINT8: - case Rok4Format::TIFF_PKB_UINT8: { - uint8_t* data = new uint8_t[image->get_width() * bands * sizeof(uint8_t)]; - image->get_line(data, j); - for (int b = 0; b < bands; b++) { - std::stringstream ss; - ss << (int)data[bands * i + b]; - gfi_data.push_back(ss.str()); - } - delete[] data; - break; - } - case Rok4Format::TIFF_RAW_FLOAT32: - case Rok4Format::TIFF_LZW_FLOAT32: - case Rok4Format::TIFF_ZIP_FLOAT32: - case Rok4Format::TIFF_PKB_FLOAT32: { - float* data = new float[image->get_width() * bands * sizeof(float)]; - image->get_line(data, j); - for (int b = 0; b < bands; b++) { - std::stringstream ss; - ss.setf(std::ios::fixed, std::ios::floatfield); - ss.precision(2); - ss << data[bands * i + b]; - gfi_data.push_back(ss.str()); - } - delete[] data; - break; - } - default: - throw WmsException::get_error_message("No readable data found", "Not Found", 404); - } - - delete image; - - return Utils::format_get_feature_info(gfi_data, info_format); - } else if (gfi_type.compare("EXTERNALWMS") == 0) { - BOOST_LOG_TRIVIAL(debug) << "GFI sur WMS externe, en projection native ou non"; - - std::map query_params; - query_params.emplace("VERSION", "1.3.0"); - query_params.emplace("SERVICE", "WMS"); - query_params.emplace("REQUEST", "GetFeatureInfo"); - query_params.emplace("STYLES", ""); - query_params.emplace("LAYERS", layer->get_gfi_layers()); - query_params.emplace("QUERY_LAYERS", layer->get_gfi_query_layers()); - query_params.emplace("INFO_FORMAT", info_format); - query_params.emplace("FORMAT", "image/tiff"); - query_params.emplace("FEATURE_COUNT", std::to_string(feature_count)); - query_params.emplace("CRS", crs->get_request_code()); - query_params.emplace("WIDTH", std::to_string(width)); - query_params.emplace("HEIGHT", std::to_string(height)); - query_params.emplace("I", std::to_string(i)); - query_params.emplace("J", std::to_string(j)); - query_params.emplace("BBOX", str_bbox); - - std::map extra_query_params = layer->get_gfi_extra_params(); - query_params.insert(extra_query_params.begin(), extra_query_params.end()); - - Request* gfi_request = new Request("GET", layer->get_gfi_url(), query_params); - - RawDataStream* response = gfi_request->send(); - delete gfi_request; - - if (response == NULL) { - throw WmsException::get_error_message("No readable data found", "Not Found", 404); - } - - return response; + std::string error; + DataStream* d = Map::get_feature_info( + services, services->map_reprojection, services->map_max_tile_x, services->map_max_tile_y, + layers, query_layers, width, height, crs, bbox, str_bbox, styles, format, format_options, dpi, + i, j, feature_count, info_format, + &error + ); + if (d == NULL) { + throw WmsException::get_error_message(error, "InvalidParameterValue", 400); } - - throw WmsException::get_error_message("Get Feature Info badly configured", "Bad configuration", 503); + return d; } \ No newline at end of file diff --git a/src/services/wms/getmap.cpp b/src/services/wms/getmap.cpp index 59adb21..1623c52 100644 --- a/src/services/wms/getmap.cpp +++ b/src/services/wms/getmap.cpp @@ -46,23 +46,12 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "services/wms/Exception.h" #include "services/wms/Service.h" -#include "Rok4Server.h" +#include "core/Rok4Server.h" +#include "core/Map.h" -DataStream* WmsService::get_map ( Request* req, Rok4Server* serv ) { +DataStream* WmsService::get_map ( Request* req, ServicesConfiguration* services ) { // Les couches std::vector layers; @@ -73,8 +62,8 @@ DataStream* WmsService::get_map ( Request* req, Rok4Server* serv ) { std::vector vector_layers; boost::split(vector_layers, str_layers, boost::is_any_of(",")); - if ( vector_layers.size() > max_layers_count ) { - throw WmsException::get_error_message("Number of layers exceed the limit (" + std::to_string(max_layers_count) + ")", "InvalidParameterValue", 400); + if ( vector_layers.size() > services->map_max_layers_count ) { + throw WmsException::get_error_message("Number of layers exceed the limit (" + std::to_string(services->map_max_layers_count) + ")", "InvalidParameterValue", 400); } for (unsigned int i = 0 ; i < vector_layers.size(); i++ ) { @@ -84,10 +73,13 @@ DataStream* WmsService::get_map ( Request* req, Rok4Server* serv ) { throw WmsException::get_error_message("Layer unknown", "LayerNotDefined", 400); } - Layer* layer = serv->get_server_configuration()->get_layer(vector_layers.at(i)); + Layer* layer = services->get_layer(vector_layers.at(i)); if (layer == NULL || ! layer->is_wms_enabled()) { throw WmsException::get_error_message("Layer " + vector_layers.at(i) + " unknown", "LayerNotDefined", 400); } + if (! layer->is_raster()) { + throw WmsException::get_error_message("Vector data " + vector_layers.at(i) + " cannot be requested with WMS GetMap", "InvalidParameterValue", 400); + } layers.push_back ( layer ); } @@ -101,8 +93,8 @@ DataStream* WmsService::get_map ( Request* req, Rok4Server* serv ) { if ( width <= 0 ) throw WmsException::get_error_message("WIDTH query parameter have to be a strictly positive integer", "InvalidParameterValue", 400); - if ( width > max_width ) - throw WmsException::get_error_message("WIDTH query parameter exceed the limit (" + std::to_string(max_width) + ")", "InvalidParameterValue", 400); + if ( width > services->map_max_width ) + throw WmsException::get_error_message("WIDTH query parameter exceed the limit (" + std::to_string(services->map_max_width) + ")", "InvalidParameterValue", 400); // La hauteur int height; @@ -113,8 +105,8 @@ DataStream* WmsService::get_map ( Request* req, Rok4Server* serv ) { if ( height <= 0 ) throw WmsException::get_error_message("HEIGHT query parameter have to be a strictly positive integer", "InvalidParameterValue", 400); - if ( height > max_height ) - throw WmsException::get_error_message("HEIGHT query parameter exceed the limit (" + std::to_string(max_width) + ")", "InvalidParameterValue", 400); + if ( height > services->map_max_height ) + throw WmsException::get_error_message("HEIGHT query parameter exceed the limit (" + std::to_string(services->map_max_height) + ")", "InvalidParameterValue", 400); // le CRS CRS* crs; @@ -131,10 +123,10 @@ DataStream* WmsService::get_map ( Request* req, Rok4Server* serv ) { throw WmsException::get_error_message("CRS " + str_crs + " unknown", "InvalidParameterValue", 400); } - if (! is_available_crs(str_crs) ) { + if (! services->is_map_available_crs(str_crs) ) { for ( unsigned int i = 0; i < layers.size() ; i++ ) { - bool crs_equals = serv->get_services_configuration()->are_crs_equals(crs->get_request_code(), layers.at(i)->get_pyramid()->get_tms()->get_crs()->get_request_code()); - if (! crs_equals && (! reprojection || ! layers.at ( i )->is_available_crs(str_crs)) ) { + bool crs_equals = services->are_crs_equals(crs->get_request_code(), layers.at(i)->get_pyramid()->get_tms()->get_crs()->get_request_code()); + if (! crs_equals && (! services->map_reprojection || ! layers.at ( i )->is_available_crs(str_crs)) ) { throw WmsException::get_error_message("CRS is not available for the layer " + layers.at ( i )->get_id(), "InvalidParameterValue", 400); } } @@ -150,7 +142,7 @@ DataStream* WmsService::get_map ( Request* req, Rok4Server* serv ) { throw WmsException::get_error_message("Format unknown", "InvalidParameterValue", 400); } - if (! is_available_format(format)) { + if (! services->is_map_available_format(format)) { throw WmsException::get_error_message("Format " + format + " unknown", "InvalidParameterValue", 400); } @@ -246,130 +238,17 @@ DataStream* WmsService::get_map ( Request* req, Rok4Server* serv ) { throw WmsException::get_error_message("DPI query parameter have to be a positive integer", "InvalidParameterValue", 400); } - // Traitement de la requête - - std::vector images; - - // Le format des canaux sera identifié à partir des données en entrée, en prenant en compte le style - SampleFormat::eSampleFormat sample_format = SampleFormat::UNKNOWN; - int nodata; - - // Le nombre de canaux dans l'image finale sera égale au nombre maximum dans les données en entrée (en prenant en compte le style) - int bands = 0; - - for (int i = 0; i < layers.size(); i++) { - bool crs_equals = serv->get_services_configuration()->are_crs_equals(crs->get_request_code(), layers.at(i)->get_pyramid()->get_tms()->get_crs()->get_request_code()); - - if (! crs_equals && ! reprojection) { - throw WmsException::get_error_message("Reprojection is not available", "InvalidParameterValue", 400); - } - - Style* style = styles.at(i); - - // On vérifie que toutes les images ont bien le même format de canal, après application du style - if (sample_format != SampleFormat::UNKNOWN && sample_format != style->get_sample_format(layers.at(i)->get_pyramid()->get_sample_format())) { - throw WmsException::get_error_message("All layers (with their style) have to own the same sample format (int or float)", "InvalidParameterValue", 400); - } else { - sample_format = style->get_sample_format(layers.at(i)->get_pyramid()->get_sample_format()); - - // Dans le cas d'un geotiff, on renseigne la valeur de nodata - // on ne peut mettre qu'une valeur, ce sera celle du premier canal du nodata de la première couche (après style) - nodata = *(style->get_output_nodata_value(layers.at(i)->get_pyramid()->get_nodata_value())); - } - - Image* image = layers.at(i)->get_pyramid()->getbbox(max_tile_x, max_tile_y, bbox, width, height, crs, crs_equals, layers.at(i)->get_resampling(), dpi); - - if (image == NULL) { - throw WmsException::get_error_message("BBOX too big", "InvalidParameterValue", 400); - } - - StyledImage* s_image = StyledImage::create(image,style); - image = s_image; - images.push_back(image); - - // Le nombre final de canaux est celui maxiumum parmis les couches, c'est à dire celui de la donnée en prenant en compte le style - bands = std::max(bands, image->get_channels()); - } - - // On construit la réponse finale, en superposant les couches - - Image* final_image; - - if (images.size() >= 2) { - int background_value[bands]; - memset(background_value, 0, bands * sizeof(int)); - final_image = MergeImage::create(images, bands, background_value, NULL, Merge::ALPHATOP); - } else { - final_image = images.at(0); - } - - final_image->set_bbox(bbox); - final_image->set_crs(crs); - if (format == "image/png" && sample_format == SampleFormat::UINT8) { - return new PNGEncoder(final_image, NULL); - } - else if (format == "image/tiff" || format == "image/geotiff") { - bool is_geotiff = (format == "image/geotiff"); - - std::map::iterator it = format_options.find("compression"); - std::string opt = ""; - if (it != format_options.end()) { - opt = it->second; - } - - if (sample_format == SampleFormat::UINT8) { - if (opt.compare("lzw") == 0) { - return new TiffLZWEncoder(final_image, is_geotiff, nodata); - } - if (opt.compare("deflate") == 0) { - return new TiffDeflateEncoder(final_image, is_geotiff, nodata); - } - if (opt.compare("raw") == 0 || opt == "") { - return new TiffRawEncoder(final_image, is_geotiff, nodata); - } - if (opt.compare("packbits") == 0) { - return new TiffPackBitsEncoder(final_image, is_geotiff, nodata); - } - } - else if (sample_format == SampleFormat::FLOAT32) { - if (opt.compare("lzw") == 0) { - return new TiffLZWEncoder(final_image, is_geotiff, nodata); - } - if (opt.compare("deflate") == 0) { - return new TiffDeflateEncoder(final_image, is_geotiff, nodata); - } - if (opt.compare("raw") == 0 || opt == "") { - return new TiffRawEncoder(final_image, is_geotiff, nodata); - } - if (opt.compare("packbits") == 0) { - return new TiffPackBitsEncoder(final_image, is_geotiff, nodata); - } - } - - delete final_image; - throw WmsException::get_error_message("Used data and expected format are not consistent", "InvalidParameterValue", 400); - } - else if (format == "image/jpeg" && sample_format == SampleFormat::UINT8 && bands == 3) { - - std::map::iterator it = format_options.find("quality"); - int quality = 75; - if (it != format_options.end()) { - // si on n'arrive pas à paser en entier l'option, on remet 75 - if (sscanf(it->second.c_str(), "%d", &quality) != 1) quality = 75; - } - - return new JPEGEncoder(final_image, quality); - } - else if (format == "image/x-bil;bits=32" && sample_format == SampleFormat::FLOAT32) { - return new BilEncoder(final_image); + // Traitement de la requête + std::string error; + DataStream* d = Map::get_map( + services, services->map_reprojection, services->map_max_tile_x, services->map_max_tile_y, + layers, width, height, crs, bbox, styles, format, format_options, dpi, + &error + ); + if (d == NULL) { + throw WmsException::get_error_message(error, "InvalidParameterValue", 400); } - else if (format == "text/asc" && sample_format == SampleFormat::FLOAT32 && final_image->get_channels() == 1) { - return new AscEncoder(final_image); - } else { + return d; - delete final_image; - throw WmsException::get_error_message("Used data format (" + std::to_string(bands) + " band(s) " + SampleFormat::to_string(sample_format) + ") and expected output format (" + format + ") are not consistent", "InvalidParameterValue", 400); - } - return NULL; } \ No newline at end of file diff --git a/src/services/wmts/Exception.h b/src/services/wmts/Exception.h index 8162d42..e803297 100644 --- a/src/services/wmts/Exception.h +++ b/src/services/wmts/Exception.h @@ -46,9 +46,9 @@ #pragma once #include -#include "boost/format.hpp" +#include -#include "DataStreams.h" +#include "core/DataStreams.h" /** * \author Institut national de l'information géographique et forestière diff --git a/src/services/wmts/Service.cpp b/src/services/wmts/Service.cpp index 896409c..0f26fa8 100644 --- a/src/services/wmts/Service.cpp +++ b/src/services/wmts/Service.cpp @@ -49,9 +49,9 @@ #include "services/wmts/Exception.h" #include "services/wmts/Service.h" -#include "Rok4Server.h" +#include "core/Rok4Server.h" -WmtsService::WmtsService (json11::Json& doc) : Service(doc), metadata(NULL) { +WmtsService::WmtsService (json11::Json& doc) : Service(doc, "WMTS service", "WMTS service", "http://localhost/wmts", "/wmts") { if (! is_ok()) { // Le constructeur du service générique a détecté une erreur, on ajoute simplement le service concerné dans le message @@ -63,90 +63,9 @@ WmtsService::WmtsService (json11::Json& doc) : Service(doc), metadata(NULL) { // Le service a déjà été mis comme n'étant pas actif return; } - - if (doc["title"].is_string()) { - title = doc["title"].string_value(); - } else if (! doc["title"].is_null()) { - error_message = "WMTS service: title have to be a string"; - return; - } else { - title = "WMTS service"; - } - - if (doc["abstract"].is_string()) { - abstract = doc["abstract"].string_value(); - } else if (! doc["abstract"].is_null()) { - error_message = "WMTS service: abstract have to be a string"; - return; - } else { - abstract = "WMTS service"; - } - - if (doc["keywords"].is_array()) { - for (json11::Json kw : doc["keywords"].array_items()) { - if (kw.is_string()) { - keywords.push_back(Keyword ( kw.string_value())); - } else { - error_message = "WMTS service: keywords have to be a string array"; - return; - } - } - } else if (! doc["keywords"].is_null()) { - error_message = "WMTS service: keywords have to be a string array"; - return; - } - - if (doc["endpoint_uri"].is_string()) { - endpoint_uri = doc["endpoint_uri"].string_value(); - } else if (! doc["endpoint_uri"].is_null()) { - error_message = "WMTS service: endpoint_uri have to be a string"; - return; - } else { - endpoint_uri = "http://localhost/wmts"; - } - - if (doc["root_path"].is_string()) { - root_path = doc["root_path"].string_value(); - } else if (! doc["root_path"].is_null()) { - error_message = "WMTS service: root_path have to be a string"; - return; - } else { - root_path = "/wmts"; - } - - if (doc["metadata"].is_object()) { - metadata = new Metadata ( doc["metadata"] ); - if (metadata->get_missing_field() != "") { - error_message = "WMTS service: invalid metadata: have to own a field " + metadata->get_missing_field(); - return ; - } - } - - if (doc["reprojection"].is_bool()) { - reprojection = doc["reprojection"].bool_value(); - } else if (! doc["reprojection"].is_null()) { - error_message = "WMTS service: reprojection have to be a boolean"; - return; - } else { - reprojection = false; - } - - if (doc["inspire"].is_bool()) { - default_inspire = doc["inspire"].bool_value(); - } else if (! doc["inspire"].is_null()) { - error_message = "WMTS service: inspire have to be a boolean"; - return; - } else { - default_inspire = false; - } - - info_formats.push_back("text/plain"); - info_formats.push_back("text/xml"); - info_formats.push_back("text/html"); - info_formats.push_back("application/json"); } -DataStream* WmtsService::process_request(Request* req, Rok4Server* serv) { +DataStream* WmtsService::process_request(Request* req, ServicesConfiguration* services) { BOOST_LOG_TRIVIAL(debug) << "WMTS service"; // On contrôle le service précisé en paramètre de requête @@ -174,23 +93,15 @@ DataStream* WmtsService::process_request(Request* req, Rok4Server* serv) { if (param_request == "getcapabilities") { BOOST_LOG_TRIVIAL(debug) << "GETCAPABILITIES request"; - return get_capabilities(req, serv); + return get_capabilities(req, services); } else if (param_request == "getfeatureinfo") { BOOST_LOG_TRIVIAL(debug) << "GETFEATUREINFO request"; - return get_feature_info(req, serv); + return get_feature_info(req, services); } else if (param_request == "gettile") { BOOST_LOG_TRIVIAL(debug) << "GETTILE request"; - return get_tile(req, serv); + return get_tile(req, services); } else { throw WmtsException::get_error_message("REQUEST query parameter unknown", "OperationNotSupported", 400); } -}; - -bool WmtsService::is_available_infoformat(std::string f) { - return (std::find(info_formats.begin(), info_formats.end(), f) != info_formats.end()); -} - -std::vector* WmtsService::get_available_infoformats() { - return &info_formats; -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/services/wmts/Service.h b/src/services/wmts/Service.h index c427a60..8cf33f3 100644 --- a/src/services/wmts/Service.h +++ b/src/services/wmts/Service.h @@ -48,7 +48,6 @@ class WmtsService; #pragma once #include "services/Service.h" -#include "configurations/Metadata.h" /** * \author Institut national de l'information géographique et forestière @@ -58,21 +57,15 @@ class WmtsService; class WmtsService : public Service { private: - DataStream* get_capabilities ( Request* req, Rok4Server* serv ); - DataStream* get_feature_info ( Request* req, Rok4Server* serv ); - DataStream* get_tile ( Request* req, Rok4Server* serv ); - - Metadata* metadata; - bool reprojection; - std::vector info_formats; - - bool default_inspire; + DataStream* get_capabilities ( Request* req, ServicesConfiguration* services ); + DataStream* get_feature_info ( Request* req, ServicesConfiguration* services ); + DataStream* get_tile ( Request* req, ServicesConfiguration* services ); std::string cache_getcapabilities; std::string cache_getcapabilities_inspire; public: - DataStream* process_request(Request* req, Rok4Server* serv); + DataStream* process_request(Request* req, ServicesConfiguration* services ); /** * \~french @@ -101,35 +94,7 @@ class WmtsService : public Service { * \~english * \brief Destructor */ - ~WmtsService() { - if (metadata) delete metadata; - }; - - /** - * \~french - * \brief La reprojection est-elle activée - * \~english - * \brief Is reprojection enabled - */ - bool reprojection_enabled() { - return reprojection; - }; - - /** - * \~french - * \brief Teste la validité du info format - * \~english - * \brief Test if info format is valid - */ - bool is_available_infoformat(std::string f) ; - - /** - * \~french - * \brief Liste des formats d'information du service - * \~english - * \brief Service informations formats - */ - std::vector* get_available_infoformats() ; + ~WmtsService() {}; }; diff --git a/src/services/wmts/getcapabilities.cpp b/src/services/wmts/getcapabilities.cpp index 2cb50dc..2818908 100644 --- a/src/services/wmts/getcapabilities.cpp +++ b/src/services/wmts/getcapabilities.cpp @@ -54,9 +54,11 @@ using boost::property_tree::xml_writer_settings; #include "services/wmts/Exception.h" #include "services/wmts/Service.h" -#include "Rok4Server.h" +#include "core/Rok4Server.h" -DataStream* WmtsService::get_capabilities ( Request* req, Rok4Server* serv ) { +DataStream* WmtsService::get_capabilities ( Request* req, ServicesConfiguration* services ) { + + bool default_inspire = services->default_inspire; if ( req->is_inspire(default_inspire) && ! cache_getcapabilities_inspire.empty()) { return new MessageDataStream ( cache_getcapabilities_inspire, "text/xml", 200 ); @@ -65,8 +67,6 @@ DataStream* WmtsService::get_capabilities ( Request* req, Rok4Server* serv ) { return new MessageDataStream ( cache_getcapabilities, "text/xml", 200 ); } - ServicesConfiguration* services = serv->get_services_configuration(); - // On va mémoriser les TMS utilisés, avec les niveaux du haut et du bas // La clé est un triplet : nom du TMS, niveau du haut, niveau du bas std::map< std::string, TileMatrixSetInfos*> used_tms_list; @@ -147,7 +147,7 @@ DataStream* WmtsService::get_capabilities ( Request* req, Rok4Server* serv ) { ptree& contents_node = root.add("Contents", ""); - std::map::iterator layers_iterator ( serv->get_server_configuration()->get_layers().begin() ), layers_end ( serv->get_server_configuration()->get_layers().end() ); + std::map::iterator layers_iterator ( services->get_layers().begin() ), layers_end ( services->get_layers().end() ); for ( ; layers_iterator != layers_end; ++layers_iterator ) { layers_iterator->second->add_node_wmts(contents_node, this, req->is_inspire(default_inspire), &used_tms_list); } diff --git a/src/services/wmts/getfeatureinfo.cpp b/src/services/wmts/getfeatureinfo.cpp index 72be18b..0015a86 100644 --- a/src/services/wmts/getfeatureinfo.cpp +++ b/src/services/wmts/getfeatureinfo.cpp @@ -47,9 +47,9 @@ #include "services/wmts/Exception.h" #include "services/wmts/Service.h" -#include "Rok4Server.h" +#include "core/Rok4Server.h" -DataStream* WmtsService::get_feature_info ( Request* req, Rok4Server* serv ) { +DataStream* WmtsService::get_feature_info ( Request* req, ServicesConfiguration* services ) { // La couche std::string str_layer = req->get_query_param("layer"); @@ -60,7 +60,7 @@ DataStream* WmtsService::get_feature_info ( Request* req, Rok4Server* serv ) { throw WmtsException::get_error_message("Layer unknown", "InvalidParameterValue", 400); } - Layer* layer = serv->get_server_configuration()->get_layer(str_layer); + Layer* layer = services->get_layer(str_layer); if (layer == NULL || ! layer->is_wmts_enabled()) { throw WmtsException::get_error_message("Layer " + str_layer + " unknown", "InvalidParameterValue", 400); } @@ -129,7 +129,7 @@ DataStream* WmtsService::get_feature_info ( Request* req, Rok4Server* serv ) { } Style* style = NULL; - if (Rok4Format::is_raster(layer->get_pyramid()->get_format())) { + if (layer->is_raster()) { style = layer->get_style_by_identifier(str_style); if (style == NULL) throw WmtsException::get_error_message("Style " + str_style + " unknown", "InvalidParameterValue", 400); @@ -146,7 +146,7 @@ DataStream* WmtsService::get_feature_info ( Request* req, Rok4Server* serv ) { throw WmtsException::get_error_message("InfoFormat unknown", "InvalidParameterValue", 400); } - if ( ! is_available_infoformat(info_format) ) + if ( ! services->is_available_infoformat(info_format) ) throw WmtsException::get_error_message("InfoFormat " + info_format + " unknown", "InvalidParameterValue", 400); // i diff --git a/src/services/wmts/gettile.cpp b/src/services/wmts/gettile.cpp index c3a954f..aa55e45 100644 --- a/src/services/wmts/gettile.cpp +++ b/src/services/wmts/gettile.cpp @@ -57,11 +57,12 @@ #include #include -#include "Rok4Server.h" +#include "core/Rok4Server.h" #include "services/wmts/Exception.h" #include "services/wmts/Service.h" +#include "core/Tile.h" -DataStream* WmtsService::get_tile(Request* req, Rok4Server* serv) { +DataStream* WmtsService::get_tile(Request* req, ServicesConfiguration* services ) { // La couche std::string str_layer = req->get_query_param("layer"); if (str_layer == "") throw WmtsException::get_error_message("LAYER query parameter missing", "MissingParameterValue", 400); @@ -71,7 +72,7 @@ DataStream* WmtsService::get_tile(Request* req, Rok4Server* serv) { throw WmtsException::get_error_message("Layer unknown", "InvalidParameterValue", 400); } - Layer* layer = serv->get_server_configuration()->get_layer(str_layer); + Layer* layer = services->get_layer(str_layer); if (layer == NULL || !layer->is_wmts_enabled()) { throw WmtsException::get_error_message("Layer " + str_layer + " unknown", "InvalidParameterValue", 400); } @@ -89,6 +90,9 @@ DataStream* WmtsService::get_tile(Request* req, Rok4Server* serv) { if (tmsi == NULL) { throw WmtsException::get_error_message("Tile matrix set " + str_tms + " unknown", "InvalidParameterValue", 400); } + if (tmsi->tms->get_id() != layer->get_pyramid()->get_tms()->get_id() && ! services->tile_reprojection) { + throw WmtsException::get_error_message("Tile matrix set " + str_tms + " unknown", "InvalidParameterValue", 400); + } // Le niveau std::string str_tm = req->get_query_param("tilematrix"); @@ -150,138 +154,16 @@ DataStream* WmtsService::get_tile(Request* req, Rok4Server* serv) { } Style* style = NULL; - if (Rok4Format::is_raster(layer->get_pyramid()->get_format())) { + if (layer->is_raster()) { style = layer->get_style_by_identifier(str_style); if (style == NULL) throw WmtsException::get_error_message("Style " + str_style + " unknown", "InvalidParameterValue", 400); } // Traitement de la requête - - if (tmsi->tms->get_id() == layer->get_pyramid()->get_tms()->get_id()) { - // TMS d'interrogation natif - Level* level = layer->get_pyramid()->get_level(tm->get_id()); - - DataSource* d = level->get_tile(column, row); - if (d == NULL) { - throw WmtsException::get_error_message("No data found", "Not Found", 404); - } - - if (layer->get_pyramid()->get_channels() == 1 && format == "image/png" && style->get_palette() && ! style->get_palette()->is_empty()) { - return new DataStreamFromDataSource(new PaletteDataSource(d, style->get_palette())); - } else { - return new DataStreamFromDataSource(d); - } - } else if (reprojection) { - // TMS d'interrogation à la demande - - BoundingBox bbox = tm->tile_indices_to_bbox(column, row); - int height = tm->get_tile_height(); - int width = tm->get_tile_width(); - CRS* crs = tmsi->tms->get_crs(); - bbox.crs = crs->get_request_code(); - - bool crs_equals = serv->get_services_configuration()->are_crs_equals(layer->get_pyramid()->get_tms()->get_crs()->get_proj_code(), crs->get_proj_code()); - - // On se donne maxium 3 tuiles sur 3 dans la pyramide source pour calculer cette tuile - Image* image = layer->get_pyramid()->getbbox(3, 3, bbox, width, height, crs, crs_equals, layer->get_resampling(), 0); - - if (image == NULL) { - BOOST_LOG_TRIVIAL(warning) << "Cannot process the tile in a non native TMS"; - throw WmtsException::get_error_message("No data found", "Not Found", 404); - } - - image->set_bbox(bbox); - image->set_crs(crs); - - std::map format_options = Utils::string_to_map(req->get_query_param("format_options"), ";", ":"); - - if (format == "image/png") { - return new PNGEncoder(image, style->get_palette()); - } - else if (format == "image/tiff" || format == "image/geotiff") { - bool is_geotiff = (format == "image/geotiff"); - - // Dans le cas d'un geotiff, on renseigne la valeur de nodata - // on ne peut mettre qu'une valeur, ce sera celle du premier canal - int nodata = *(layer->get_pyramid()->get_nodata_value()); - - std::map::iterator it = format_options.find("compression"); - std::string opt = ""; - if (it != format_options.end()) { - opt = it->second; - } - - // La donnée ne peut être retournée que dans le format de la pyramide source utilisée - - switch (layer->get_pyramid()->get_format()) { - case Rok4Format::TIFF_RAW_UINT8: - case Rok4Format::TIFF_LZW_UINT8: - case Rok4Format::TIFF_ZIP_UINT8: - case Rok4Format::TIFF_PKB_UINT8: - if (opt.compare("lzw") == 0) { - return new TiffLZWEncoder(image, is_geotiff, nodata); - } - if (opt.compare("deflate") == 0) { - return new TiffDeflateEncoder(image, is_geotiff, nodata); - } - if (opt.compare("raw") == 0 || opt == "") { - return new TiffRawEncoder(image, is_geotiff, nodata); - } - if (opt.compare("packbits") == 0) { - return new TiffPackBitsEncoder(image, is_geotiff, nodata); - } - - break; - - case Rok4Format::TIFF_RAW_FLOAT32: - case Rok4Format::TIFF_LZW_FLOAT32: - case Rok4Format::TIFF_ZIP_FLOAT32: - case Rok4Format::TIFF_PKB_FLOAT32: - if (opt.compare("lzw") == 0) { - return new TiffLZWEncoder(image, is_geotiff, nodata); - } - if (opt.compare("deflate") == 0) { - return new TiffDeflateEncoder(image, is_geotiff, nodata); - } - if (opt.compare("raw") == 0 || opt == "") { - return new TiffRawEncoder(image, is_geotiff, nodata); - } - if (opt.compare("packbits") == 0) { - return new TiffPackBitsEncoder(image, is_geotiff, nodata); - } - - break; - default: - delete image; - throw WmtsException::get_error_message("No data found", "Not Found", 404); - } - } - else if (format == "image/jpeg") { - - std::map::iterator it = format_options.find("quality"); - int quality = 75; - if (it != format_options.end()) { - // si on n'arrive pas à paser en entier l'option, on remet 75 - if (sscanf(it->second.c_str(), "%d", &quality) != 1) quality = 75; - } - - return new JPEGEncoder(image, quality); - } - else if (format == "image/x-bil;bits=32") { - return new BilEncoder(image); - } - else if (format == "text/asc") { - // On ne traite le format asc que sur les image à un seul channel - if (image->get_channels() != 1) { - BOOST_LOG_TRIVIAL(error) << "Le format " << format << " ne concerne que les images à 1 canal"; - delete image; - throw WmtsException::get_error_message("No data found", "Not Found", 404); - } else { - return new AscEncoder(image); - } - } + DataStream* d = Tile::get_tile(services, layer, tmsi->tms, tm, column, row, format, style); + if (d == NULL) { + throw WmtsException::get_error_message("No data found", "Not Found", 404); } - // TMS d'interrogation à la demande mais reprojection non activée - throw WmtsException::get_error_message("Tile matrix set " + str_tms + " unknown", "InvalidParameterValue", 400); + return d; } \ No newline at end of file