Skip to main content

les tronçons de centralité fonctionnelle

Encore une subtilité de PostGIS ! L'erreur Only lon/lat coordinate systems are supported in geography est très parlante quand on connaît le moteur interne de la base de données.

Explication de l'erreur : Dans la base OSM de votre VPS, les géométries (l.way) sont stockées nativement en "Web Mercator" (EPSG:3857, le système de Google Maps), dont les coordonnées sont déjà exprimées en mètres (et non en degrés de longitude/latitude). Or, quand on utilise la fonction ::geography pour obtenir une distance ultra-précise (qui prend en compte la courbure de la Terre), PostgreSQL exige que la donnée source soit en Longitude/Latitude (EPSG:4326).

Il suffit donc de transformer la géométrie en 4326 juste avant de la passer en geography.

Voici la requête avec la petite correction magique ST_Transform(l.way, 4326) intégrée au calcul de longueur.

La Requête SQL (La Bonne !)

SQL
DROP TABLE IF EXISTS toulon_hierarchie_fonctionnelle;

CREATE TABLE toulon_hierarchie_fonctionnelle AS
WITH stats_troncons AS (
    SELECT 
        f.osm_id,
        f.nom_voie,
        f.code_pattern,
        COUNT(i.osm_id) as total_items,
        -- On transforme d'abord en 4326 (lon/lat) pour que la conversion geography fonctionne parfaitement
        ST_Length(ST_Transform(l.way, 4326)::geography) as longueur_rue_m,
        -- Calcul de la densité pour 200m
        CASE 
            WHEN ST_Length(ST_Transform(l.way, 4326)::geography) > 0 
            THEN (COUNT(i.osm_id)::numeric / ST_Length(ST_Transform(l.way, 4326)::geography)::numeric) * 200
            ELSE 0 
        END as items_pour_200m,
        f.geom
    FROM zones_motifs_filaires f
    JOIN planet_osm_line l ON f.osm_id = l.osm_id
    LEFT JOIN toulon_items_nomenclature_full i ON ST_Intersects(ST_Transform(i.geom, 3857), f.geom)
    GROUP BY f.osm_id, f.nom_voie, f.code_pattern, f.geom, l.way
),
classification AS (
    SELECT 
        osm_id, nom_voie, code_pattern, total_items, 
        ROUND(longueur_rue_m::numeric) as longueur_rue_m, 
        ROUND(items_pour_200m::numeric, 1) as items_pour_200m, 
        geom,
        CASE 
            -- NIVEAU 1 : Centre Urbain (>= 10 items pour un linéaire de 200m)
            WHEN items_pour_200m >= 10 THEN 1
            
            -- NIVEAU 2 : Centre Local (>= 5 items pour un linéaire de 200m)
            WHEN items_pour_200m >= 5 THEN 2
            
            -- NIVEAU 3 : Noyau de vie quotidienne (5 items ou plus sur le tronçon)
            WHEN total_items >= 5 THEN 3
            
            -- NIVEAU 4 : Espaces Résidentiels (le reste)
            ELSE 4
        END as niveau_fonctionnel
    FROM stats_troncons
)
SELECT * FROM classification 
WHERE niveau_fonctionnel < 4;

CREATE INDEX idx_hierarchie_geom ON toulon_hierarchie_fonctionnelle USING GIST(geom);

Exportation

Puis vous pouvez relancer l'export avec la commande que l'on connaît bien maintenant (après avoir fait \q) :

Bash
sudo -u postgres ogr2ogr -f "GPKG" \
    "/tmp/Toulon_Hierarchie_Fonctionnelle.gpkg" \
    PG:"dbname=alteris_db" \
    "toulon_hierarchie_fonctionnelle" && \
sudo mv /tmp/Toulon_Hierarchie_Fonctionnelle.gpkg /home/debian/osm_data/ && \
sudo chown debian:debian /home/debian/osm_data/Toulon_Hierarchie_Fonctionnelle.gpkg

Cette fois-ci, le calcul mathématique de la longueur devrait passer sans aucune erreur et générer votre cartographie des Niveaux 1, 2 et 3 !

Est-ce que la requête s'est bien exécutée cette fois ? J'ai hâte de savoir comment Toulon "réagit" à vos seuils stricts !