Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 44 additions & 35 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,44 @@
## 6.1.5

### [Fixed]

* Nettoyage et bascule des styles et TMS lors d'une extinction ou redémarrage du serveur
* `WMTS`
* pour que la couche apparaisse dans les capacités Inspire, le style par défaut doit avoir l'identifiant `<nom de la couche>.Default`
* `WMS`
* pour que la couche apparaisse dans les capacités Inspire, le style par défaut doit avoir l'identifiant `<nom de la couche>.Default`
* on vérifie que la donnée a bien 3 canaux pour répondre une tuile en JPEG
* Dans le cas d'une couche inconnu, le code est `LayerNotDefined`
* Écriture de la valeur de nodata dans les header geotiff
* `TMS`
* Dans la description des couches, les niveaux (`TileSet`) doivent être définis dans la balise `TileSets` et non `TileMap` et `Origin` est le coin en bas à gauche et non en haut à gauche

## 6.1.4

### [Fixed]

* `WMS`
* Correction de l'attribution dans les capacités : contenu du logo et ordre des balises
* Correction du géoréférencement dans les réponses GeoTIFF
* Correction de l'attribution dans les capacités : contenu du logo et ordre des balises
* Correction du géoréférencement dans les réponses GeoTIFF

* `TMS`
* Correction de l'attribution dans les capacités : contenu du logo
* Ajout du header `Content-Encoding: defalte` pour les tuiles bil compressées
* Correction de l'attribution dans les capacités : contenu du logo
* Ajout du header `Content-Encoding: deflate` pour les tuiles bil compressées

* `WMTS`
* Correction des balises de métadonnées dans les capacités
* Ajout du header `Content-Encoding: defalte` pour les tuiles bil compressées
* Correction des balises de métadonnées dans les capacités
* Ajout du header `Content-Encoding: deflate` pour les tuiles bil compressées

## 6.1.3

### [Fixed]

* `WMTS` :
* correction du calcul des tuiles limites pour le TMS natif lorsque les limites de la couche sont surchargées par une bbox
* pour que la couche apparaisse dans les capacités Inspire, le format de la tuile doit être le PNG
* dans les capacités inspire, `inspire_vs:ExtendedCapabilities` doit être dans `OperationsMetadata`
* correction du calcul des tuiles limites pour le TMS natif lorsque les limites de la couche sont surchargées par une bbox
* pour que la couche apparaisse dans les capacités Inspire, le format de la tuile doit être le PNG
* dans les capacités inspire, `inspire_vs:ExtendedCapabilities` doit être dans `OperationsMetadata`
* `WMS`
* Ajout des schémas XML dans les réponses en erreur
* Ajout des schémas XML dans les réponses en erreur

## 6.1.2

Expand Down Expand Up @@ -98,24 +113,24 @@
### [Changed]

* WMTS :
* On ajoute à la liste des TMS au niveau du getcapabilities les TMS "de base" en entier
* On ajoute à la liste des TMS au niveau du getcapabilities les TMS "de base" en entier

## 5.4.1

### [Added]

* WMS :
* Ajout de la configuration du titre et nom de la couche racine dans le getCapabilities
* Ajout de la configuration du titre et nom de la couche racine dans le getCapabilities

### [Changed]

* WMS :
* Déplacement des fonctions d'écriture d'une bbox du getCapabilities dans UtilsXML
* Ajout de bbox au niveau de la couche racine dans le getCapabilities
* L'attribution d'une couche est mise après les éventuelles métadonnées
* Déplacement des fonctions d'écriture d'une bbox du getCapabilities dans UtilsXML
* Ajout de bbox au niveau de la couche racine dans le getCapabilities
* L'attribution d'une couche est mise après les éventuelles métadonnées
* WMTS :
* On ne liste plus les couches de tuiles vectorielles dans le getCapabilities
* On exporte dans le getcapabilities un TMS différent pour chaque couple haut / bas présent dans les couches
* On ne liste plus les couches de tuiles vectorielles dans le getCapabilities
* On exporte dans le getcapabilities un TMS différent pour chaque couple haut / bas présent dans les couches

## 5.3.0

Expand Down Expand Up @@ -162,25 +177,19 @@ Implémentation partielle de l'API OGC Tiles - Part 1 [v1.0.0 final release](htt
### [Added]

* Liste de nouvelles routes pour obtenir le **GetCapabilities**:
* /tiles/collections
avec les paramètres facultatifs :
* bbox
* limit
* /tiles/collections avec les paramètres facultatifs :
* bbox
* limit
* /tiles/collections/{layer}/map/tiles
* /tiles/collections/{layer}/tiles
* /tiles/tilematrixsets
* /tiles/tilematrixsets/{tms}

* Liste des nouvelles routes pour obtenir le **GetTile** :

* Raster
* /tiles/map/tiles/{tms}/{level}/{row}/{col}
avec le paramètre obligatoire : collections={layer}
* /tiles/styles/{style}/map/tiles/{tms}/{level}/{row}/{col}
avec le paramètre obligatoire : collections={layer}
* /tiles/collections/{layer}/styles/{style}/map/tiles/{tms}/{level}/{row}/{col}
* /tiles/collections/{layer}/map/tiles/{tms}/{level}/{row}/{col}

* Raster
* /tiles/map/tiles/{tms}/{level}/{row}/{col} avec le paramètre obligatoire : collections={layer}
* /tiles/styles/{style}/map/tiles/{tms}/{level}/{row}/{col} avec le paramètre obligatoire : collections={layer}
* /tiles/collections/{layer}/styles/{style}/map/tiles/{tms}/{level}/{row}/{col}
* /tiles/collections/{layer}/map/tiles/{tms}/{level}/{row}/{col}
* Vecteur
* /tiles/tiles/{tms}/{level}/{row}/{col}?collections={layer}
* /tiles/collections/{layer}/tiles/{tms}/{level}/{row}/{col}
Expand Down Expand Up @@ -227,10 +236,10 @@ Les configurations des couches, styles et tile matrix sets peuvent être des obj
### [Added]

* Implémentation de routes de santé
* `/healthcheck` : informations générales, version, date de lancement, statut général
* `/healthcheck/info` : informations détaillées, listes de couches, styles et tile matrix sets
* `/healthcheck/depends` : informations sur les stockages, nombres de contextes par type
* `/healthcheck/threads` : informations sur les threads, statut, requêtes prises en charge, dernier temps de réponse
* `/healthcheck` : informations générales, version, date de lancement, statut général
* `/healthcheck/info` : informations détaillées, listes de couches, styles et tile matrix sets
* `/healthcheck/depends` : informations sur les stockages, nombres de contextes par type
* `/healthcheck/threads` : informations sur les threads, statut, requêtes prises en charge, dernier temps de réponse

### [Fixed]

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Serveur de diffusion WMS, WMTS et TMS

![ROK4 Logo](https://rok4.github.io/assets/images/rok4.png)
![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 :

Expand Down Expand Up @@ -224,7 +224,7 @@ Lorsqu'une couche est chargée, les descripteurs de pyramide, de TMS et de style

Pour les TMS et les styles, ils sont cherchés dans les répertoires (fichier ou objet) renseignés dans le `server.json`, avec comme nom de fichier objet `<ID du style>.json`. Un annuaire est tenu à jour pour ne charger qu'une seule fois le style ou le TMS.

![Chargement du serveur](./docs/images/rok4server-layer-pyramid.png)
![Chargement du serveur](./docs/images/rok4-server-loading.png)

### Personnalisation des points d'accès aux services

Expand Down
Binary file added docs/images/rok4-server-loading.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed docs/images/rok4server-layer-pyramid.png
Binary file not shown.
8 changes: 4 additions & 4 deletions src/Inspire.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,8 @@ bool is_inspire_wmts ( Layer* layer ) {
}

// Pour être inspire, le style par défaut doit avoir le bon identifiant
if (layer->get_default_style()->get_identifier() != "inspire_common:DEFAULT") {
BOOST_LOG_TRIVIAL(debug) << "Non conforme INSPIRE WMTS (" << layer->get_id() << ") : style par défaut != inspire_common:DEFAULT" ;
if (layer->get_default_style()->get_identifier() != layer->get_id() + ":Default") {
BOOST_LOG_TRIVIAL(debug) << "Non conforme INSPIRE WMTS (" << layer->get_id() << ") : style par défaut != " + layer->get_id() + ":Default" ;
return false;
}

Expand All @@ -174,8 +174,8 @@ bool is_inspire_wms ( Layer* layer ) {
}

// Pour être inspire, le style par défaut doit avoir le bon identifiant
if (layer->get_default_style()->get_identifier() != "inspire_common:DEFAULT") {
BOOST_LOG_TRIVIAL(debug) << "Non conforme INSPIRE WMS (" << layer->get_id() << ") : style par défaut != inspire_common:DEFAULT" ;
if (layer->get_default_style()->get_identifier() != layer->get_id() + ":Default") {
BOOST_LOG_TRIVIAL(debug) << "Non conforme INSPIRE WMS (" << layer->get_id() << ") : style par défaut != " + layer->get_id() + ":Default" ;
return false;
}

Expand Down
4 changes: 2 additions & 2 deletions src/configurations/Layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1289,14 +1289,14 @@ std::string Layer::get_description_tms(TmsService* service) {
TileMatrix* tm = pyramid->get_lowest_level()->get_tm();

root.add("Origin.<xmlattr>.x", tm->get_x0() );
root.add("Origin.<xmlattr>.y", tm->get_y0() );
root.add("Origin.<xmlattr>.y", tm->get_y0() - tm->get_matrix_height() * tm->get_tile_height() * tm->get_res() );

root.add("TileFormat.<xmlattr>.width", tm->get_tile_width() );
root.add("TileFormat.<xmlattr>.height", tm->get_tile_height() );
root.add("TileFormat.<xmlattr>.mime-type", Rok4Format::to_mime_type ( pyramid->get_format() ) );
root.add("TileFormat.<xmlattr>.extension", Rok4Format::to_extension ( pyramid->get_format() ) );

ptree& tilesets_node = root.add("TileMap", "");
ptree& tilesets_node = root.add("TileSets", "");
tilesets_node.add("<xmlattr>.profile", "none");

int order = 0;
Expand Down
15 changes: 11 additions & 4 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,10 @@ void reload_configuration ( int signum ) {
reload = true;
std::cout<< "Rechargement du serveur rok4" << "["<< getpid() <<"]" <<std::endl;

// On veut que le chargement de configuration construise de nouvelles instances des styles et TMS, qui ont potentiellement changé
TmsBook::send_to_trash();
StyleBook::send_to_trash();

rok4server_instance_tmp = load_configuration();
if ( ! rok4server_instance_tmp ){
std::cout<< "Erreur lors du rechargement du serveur rok4" << "["<< getpid() <<"]" <<std::endl;
Expand Down Expand Up @@ -363,8 +367,6 @@ int main ( int argc, char** argv ) {
std::cout<< "Servers switch " << "["<< pid <<"]" <<std::endl;
rok4server_instance = rok4server_instance_tmp;
rok4server_instance_tmp = 0;
TmsBook::empty_trash();
StyleBook::empty_trash();
}
rok4server_instance->set_fcgi_socket ( sock );
}
Expand All @@ -379,16 +381,21 @@ int main ( int argc, char** argv ) {

rok4server_instance->run(signal_pending);

TmsBook::send_to_trash();
StyleBook::send_to_trash();

if ( reload ) {
// Rechargement du serveur
BOOST_LOG_TRIVIAL(info) << "Configuration reload" ;
sock = rok4server_instance->get_fcgi_socket();
// Lors du rechargement on a mis à la poubelle tous les anciens TMS et styles
// On peut maintenant les supprimer
TmsBook::empty_trash();
StyleBook::empty_trash();
} else {
// Extinction du serveur
BOOST_LOG_TRIVIAL(info) << "Server shutdown" ;
// On va vouloir supprimer tous les styles et TMS, on les envoie donc à la poubelle
TmsBook::send_to_trash();
StyleBook::send_to_trash();
}

delete rok4server_instance;
Expand Down
20 changes: 12 additions & 8 deletions src/services/tiles/gettile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,25 +232,29 @@ DataStream* TilesService::get_tile ( Request* req, Rok4Server* serv, bool is_map
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<uint8_t>(image, is_geotiff);
return new TiffRawEncoder<uint8_t>(image, is_geotiff, nodata);
case Rok4Format::TIFF_LZW_UINT8:
return new TiffLZWEncoder<uint8_t>(image, is_geotiff);
return new TiffLZWEncoder<uint8_t>(image, is_geotiff, nodata);
case Rok4Format::TIFF_ZIP_UINT8:
return new TiffDeflateEncoder<uint8_t>(image, is_geotiff);
return new TiffDeflateEncoder<uint8_t>(image, is_geotiff, nodata);
case Rok4Format::TIFF_PKB_UINT8:
return new TiffPackBitsEncoder<uint8_t>(image, is_geotiff);
return new TiffPackBitsEncoder<uint8_t>(image, is_geotiff, nodata);
case Rok4Format::TIFF_RAW_FLOAT32:
return new TiffRawEncoder<float>(image, is_geotiff);
return new TiffRawEncoder<float>(image, is_geotiff, nodata);
case Rok4Format::TIFF_LZW_FLOAT32:
return new TiffLZWEncoder<float>(image, is_geotiff);
return new TiffLZWEncoder<float>(image, is_geotiff, nodata);
case Rok4Format::TIFF_ZIP_FLOAT32:
return new TiffDeflateEncoder<float>(image, is_geotiff);
return new TiffDeflateEncoder<float>(image, is_geotiff, nodata);
case Rok4Format::TIFF_PKB_FLOAT32:
return new TiffPackBitsEncoder<float>(image, is_geotiff);
return new TiffPackBitsEncoder<float>(image, is_geotiff, nodata);
default:
delete image;
throw TilesException::get_error_message("ResourceNotFound", "Not data found", 404);
Expand Down
4 changes: 2 additions & 2 deletions src/services/wms/getfeatureinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,12 @@ DataStream* WmsService::get_feature_info ( Request* req, Rok4Server* serv ) {

if (contain_chars(vector_layers.at(i), "<>")) {
BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in WMS layer: " << vector_layers.at(i);
throw WmsException::get_error_message("Layer unknown", "InvalidParameterValue", 400);
throw WmsException::get_error_message("Layer unknown", "LayerNotDefined", 400);
}

Layer* layer = serv->get_server_configuration()->get_layer(vector_layers.at(i));
if (layer == NULL || ! layer->is_wms_enabled()) {
throw WmsException::get_error_message("Layer " + vector_layers.at(i) + " unknown", "InvalidParameterValue", 400);
throw WmsException::get_error_message("Layer " + vector_layers.at(i) + " unknown", "LayerNotDefined", 400);
}

layers.push_back ( layer );
Expand Down
28 changes: 16 additions & 12 deletions src/services/wms/getmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,12 @@ DataStream* WmsService::get_map ( Request* req, Rok4Server* serv ) {

if (contain_chars(vector_layers.at(i), "<>")) {
BOOST_LOG_TRIVIAL(warning) << "Forbidden char detected in WMS layer: " << vector_layers.at(i);
throw WmsException::get_error_message("Layer unknown", "InvalidParameterValue", 400);
throw WmsException::get_error_message("Layer unknown", "LayerNotDefined", 400);
}

Layer* layer = serv->get_server_configuration()->get_layer(vector_layers.at(i));
if (layer == NULL || ! layer->is_wms_enabled()) {
throw WmsException::get_error_message("Layer " + vector_layers.at(i) + " unknown", "InvalidParameterValue", 400);
throw WmsException::get_error_message("Layer " + vector_layers.at(i) + " unknown", "LayerNotDefined", 400);
}

layers.push_back ( layer );
Expand Down Expand Up @@ -253,6 +253,7 @@ DataStream* WmsService::get_map ( Request* req, Rok4Server* serv ) {

// 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;
Expand All @@ -271,8 +272,11 @@ DataStream* WmsService::get_map ( Request* req, Rok4Server* serv ) {
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);

Expand Down Expand Up @@ -317,37 +321,37 @@ DataStream* WmsService::get_map ( Request* req, Rok4Server* serv ) {

if (sample_format == SampleFormat::UINT8) {
if (opt.compare("lzw") == 0) {
return new TiffLZWEncoder<uint8_t>(final_image, is_geotiff);
return new TiffLZWEncoder<uint8_t>(final_image, is_geotiff, nodata);
}
if (opt.compare("deflate") == 0) {
return new TiffDeflateEncoder<uint8_t>(final_image, is_geotiff);
return new TiffDeflateEncoder<uint8_t>(final_image, is_geotiff, nodata);
}
if (opt.compare("raw") == 0 || opt == "") {
return new TiffRawEncoder<uint8_t>(final_image, is_geotiff);
return new TiffRawEncoder<uint8_t>(final_image, is_geotiff, nodata);
}
if (opt.compare("packbits") == 0) {
return new TiffPackBitsEncoder<uint8_t>(final_image, is_geotiff);
return new TiffPackBitsEncoder<uint8_t>(final_image, is_geotiff, nodata);
}
}
else if (sample_format == SampleFormat::FLOAT32) {
if (opt.compare("lzw") == 0) {
return new TiffLZWEncoder<float>(final_image, is_geotiff);
return new TiffLZWEncoder<float>(final_image, is_geotiff, nodata);
}
if (opt.compare("deflate") == 0) {
return new TiffDeflateEncoder<float>(final_image, is_geotiff);
return new TiffDeflateEncoder<float>(final_image, is_geotiff, nodata);
}
if (opt.compare("raw") == 0 || opt == "") {
return new TiffRawEncoder<float>(final_image, is_geotiff);
return new TiffRawEncoder<float>(final_image, is_geotiff, nodata);
}
if (opt.compare("packbits") == 0) {
return new TiffPackBitsEncoder<float>(final_image, is_geotiff);
return new TiffPackBitsEncoder<float>(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) {
else if (format == "image/jpeg" && sample_format == SampleFormat::UINT8 && bands == 3) {

std::map<std::string, std::string>::iterator it = format_options.find("quality");
int quality = 75;
Expand Down
Loading