<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>PostGis on Mon Blogue</title>
    <link>https://blog.velocarte66.fr/fr/tags/postgis/</link>
    <description>Recent content in PostGis on Mon Blogue</description>
    <image>
      <title>Mon Blogue</title>
      <url>https://blog.velocarte66.fr/images/papermod-cover.png</url>
      <link>https://blog.velocarte66.fr/images/papermod-cover.png</link>
    </image>
    <generator>Hugo</generator>
    <language>fr</language>
    <lastBuildDate>Fri, 04 Oct 2013 18:51:52 +0200</lastBuildDate>
    <atom:link href="https://blog.velocarte66.fr/fr/tags/postgis/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>OSM: Utiliser les attributs de l&#39;admin_centre pour rendre des limites administratives</title>
      <link>https://blog.velocarte66.fr/fr/posts/osm-utiliser-les-attributs-de-ladmin_centre-pour-rendre-des-limites-administratives/</link>
      <pubDate>Fri, 04 Oct 2013 18:51:52 +0200</pubDate>
      <guid>https://blog.velocarte66.fr/fr/posts/osm-utiliser-les-attributs-de-ladmin_centre-pour-rendre-des-limites-administratives/</guid>
      <description>&lt;div class=&#39;drupal-import&#39;&gt;
Dans la base de données OpenStreetMap, les informations sur les entités administratives (communes, départements, etc.) se trouvent généralement sur le noeud &lt;code&gt;place=*&lt;/code&gt; qui est membre de la relation du type &lt;code&gt;boundary&lt;/code&gt; avec le rôle &lt;code&gt;admin_centre&lt;/code&gt;. Si on a besoin de ces informations, comme par exemple &lt;em&gt;population&lt;/em&gt; ou &lt;em&gt;name:xx&lt;/em&gt;, pour choisir le style du polygone ou y assigner un libellée, les structures des données crées par les outils ne permettent pas d&#39;accéder aux informations du noeud &lt;code&gt;admin_centre&lt;/code&gt; à partir du polygone. Cet article présente des solutions pour les bases de données PostGis crées avec &lt;code&gt;osm2pgsql&lt;/code&gt; et les fichiers shape crées avec osmium.
&lt;!--break--&gt;
&lt;h1&gt;PostGis / osm2pgsql&lt;/h1&gt;
osm2pgsql reporte bien les attributs des chemins «outer» sur le polygone qu&#39;il crée pour une relation du type «boundary» mais pas les attributs du centre administratif. En mode «slim» osm2pgsql crée bien une table &lt;code&gt;&amp;lt;prefix&amp;gt;_rels&lt;/code&gt; qui contient pour chaque relation ses attributs et ses membres avec le rôle et l&#39;id, mais sous une forme qui n&#39;est pas directement exploitable avec SQL. Un exemple :
&lt;code&gt;&lt;pre&gt;
psql -d osm -c  &#34;select members from planet_osm_rels\
                     where hstore(tags)-&gt;&#39;name&#39;=&#39;Corneilla-la-Rivière&#39;;&#34;
                               members
----------------------------------------------------------------------------
{w121772197,outer,w100006391,outer,w121772204,outer,n287557758,admin_centre}
&lt;/pre&gt;&lt;/code&gt;
On trouve les membres d&#39;une relation dans un array, deux valeurs par membre, le type et l&#39;identificateur du membre et son rôle. Une petite fonction SQL permet d&#39;acceder à l&#39;identificateur de l&#39;admin_centre :
&lt;code&gt;&lt;pre&gt;
CREATE OR REPLACE FUNCTION admin_centre(anyarray)
   RETURNS bigint
   LANGUAGE sql
   AS $function$
      SELECT cast(substring($1[i] from 2) as bigint)
         FROM generate_series(array_lower($1,1),array_upper($1,1),2) i 
         WHERE $1[i+1]=&#39;admin_centre&#39;;$function$
&lt;/pre&gt;&lt;/code&gt;
Cette fonction permet de faire des requêtes sur les relations des limites administratives avec les attributs de leurs centres administratifs :
&lt;code&gt;&lt;pre&gt;
select poly.name, point.name, point.&#34;name:ca&#34;, point.population 
   from planet_osm_rels r, 
        planet_osm_polygon poly, 
        planet_osm_point point 
   where poly.admin_level=&#39;8&#39; 
         and admin_centre(r.members) = point.osm_id 
         and r.id = -poly.osm_id ;
&lt;/pre&gt;&lt;/code&gt;
Si ce type de requête n&#39;est pas suffisamment efficace on peut copier les attributs des noeuds sur les polygones ou bien créer un table de références :
&lt;code&gt;&lt;pre&gt;
create table admin_rel 
   as select -id as rel_id,
             admin_centre(members) as admin_centre
        from planet_osm_rels 
        where hstore(tags)-&gt;&#39;boundary&#39;=&#39;administrative&#39; and 
              hstore(tags)-&gt;&#39;admin_level&#39;  in (&#39;8&#39;,&#39;6&#39;,&#39;4&#39;);
&lt;/pre&gt;&lt;/code&gt;
&lt;h1&gt;fichiers «shape»&lt;/h1&gt;
On utilise pour cela l&#39;outil &lt;code&gt;osmjs&lt;/code&gt; et QGis. &lt;code&gt;osmjs&lt;/code&gt; basé sur la bibliothèque &lt;code&gt;osmium&lt;/code&gt; permet d&#39;extraire des objets d&#39;un fichier osm sous forme de fichier «shape». Comme &lt;code&gt;osm2pgsql&lt;/code&gt;, cet outil crée des polygones pour les relations «boundary» mais ne tient pas compte du rôle &lt;code&gt;admin_centre&lt;/code&gt;. Par contre il est possible de produire un fichier csv qui contient les identificateurs des polygones et de leurs noeuds &lt;code&gt;admin_centre&lt;/code&gt; :
&lt;code&gt;&lt;pre&gt;
/*
  Osmium Javascript Example:  shape_export.js

  run with: osmjs -2 -m -l sparsetable -j shape_export.js OSMFILE
*/

var shp_places = Osmium.Output.Shapefile.open(&#39;./places&#39;, &#39;point&#39;);
shp_places.add_field(&#39;id&#39;, &#39;string&#39;, 12);
shp_places.add_field(&#39;type&#39;, &#39;string&#39;, 32);
shp_places.add_field(&#39;name&#39;, &#39;string&#39;, 32);

var shp_boundaries = Osmium.Output.Shapefile.open(&#39;./boundaries&#39;, &#39;polygon&#39;);
shp_boundaries.add_field(&#39;id&#39;, &#39;integer&#39;, 10);
shp_boundaries.add_field(&#39;type&#39;, &#39;string&#39;, 32);
shp_boundaries.add_field(&#39;boundary&#39;, &#39;string&#39;, 255);
shp_boundaries.add_field(&#39;admin_level&#39;, &#39;string&#39;, 255);

var csv_file = Osmium.Output.CSV.open(&#34;./rels.csv&#34;);

var node_tags = {
    place: { village: &#39;villaget&#39;, city: &#39;city&#39;, town: &#39;town&#39;} //,
    //shop: { supermarket: &#39;supermarket&#39; }
}

Osmium.Callbacks.init = function() {
    print(&#34;Init&#34;);
}
Osmium.Callbacks.node = function() {
    for (var key in this.tags) {
        if (node_tags[key]) {
            var type = node_tags[key][this.tags[key]];
            if (type) {
                shp_places.add(this.geom, { id: this.id, type: type, name: this.tags.name });
            }
        }
    }
}
Osmium.Callbacks.area = function() {
    if (this.tags.boundary) {
        shp_boundaries.add(this.geom, { id: this.id, type: this.tags.boundary, admin_level: this.tags.admin_level});
    }
}
Osmium.Callbacks.relation = function() {
   for (var key in this.members) {
      for (var key2 in this.members[key]) {
         if (key2==&#39;role&#39; &amp;&amp; this.members[key].role==&#39;admin_centre&#39;){
            csv_file.print(this.id*2+1, this.members[key].ref, 
                           this.members[key].role, this.members[key].type);
         }
      }
   }
}
Osmium.Callbacks.end = function() {
    shp_places.close();
    shp_boundaries.close();
    csv_file.close();
    print(&#34;Done&#34;);
}
&lt;/pre&gt;&lt;/code&gt;
Ce scripte produit un fichier shape avec les polygones, un avec les noeuds et und fichier csv qui relie les uns aux autres par leurs identificateurs. Il tient compte du fait que &lt;code&gt;osmjs&lt;/code&gt; assigne des pseudo-identificatuers aux polygones qu&#39;il calcule avec la formule &lt;code&gt;[2 * osm_id de la relation + 1&lt;/code&gt;.

On charge ces trois fichers dans QGis. On crée une jointure des données csv avec la couche des noeuds et ensuite une jointure de la couche des polygones avec les données csv. La couche polygone a maintenant accès aux données des noeuds associés. Si on enregistre la couche polygone dans un ficher au format shape, ce fichier contiendra toutes les données et peut être utilisé avec mapnik / tilemill.


&lt;/div&gt;</description>
    </item>
  </channel>
</rss>
