x

Mapnik: Erzeugen von kombinierter Beschriftung aus mehreren Feldern


  1. Mapnik: Erzeugen von kombinierter Beschriftung aus mehreren Feldern · cziehr (Gast) · 03.05.2013 20:46 · [flux]

    Hallo,

    wie ich ja in letzter Zeit schon geschrieben habe bin ich gerade dabei eine spezielle Hydrantenkarte für eine Feuerwehr zu erstellen. Ich habe dafür Mapnik2 auf einem Ubuntu-Server laufen.

    Ich habe die OpenFireMap-Quellen erhalten und angefangen den Kartenstil etwas zu modifizieren bzw. zu erweitern (in Zoomstufe 18 soll außerdem der Druck und die Durchflussrate angegeben werden), aber irgendwie funktioniert es nicht so wirklich. Hier ein Auszug des Inhalts meiner osm.xml:

    [...]
    <Style␣name="hydrants">
    [...]
    <Rule>
    &maxscale_zoom18;
    &minscale_zoom18;
    <Filter>[fh_t]␣=␣'underground'</Filter>
    <PointSymbolizer␣file="&symbols;/hydrant_u_17.png"␣allow-overlap="true"/>
    <TextSymbolizer␣allow-overlap="true"␣fontset-name="bold-fonts"␣size="9"␣fill="#ff0000"␣dy="9"␣halo-radius="1"␣wrap-width="0">H[fh_d]␣\n␣[fh_p]␣bar␣\n␣[fh_f]</TextSymbolizer>
    </Rule>
    </Style>
    
    <Layer␣name="hydrants"␣status="on"␣srs="&osm2pgsql_projection;">
    <StyleName>hydrants</StyleName>
    <Datasource>
    <Parameter␣name="table">
    (select␣way,name,emergency,amenity,ref,
    coalesce("fire_hydrant:type",'_')␣as␣fh_t,replace(replace("fire_hydrant:diameter",'fixme','␣'),'FIXME','␣')␣as␣fh_d,
    "fire_hydrant:pressure"␣as␣fh_p,
    case␣when␣"fire_hydrant:flow_capacity"␣similar␣to␣'[[:digit:]]+'␣then
    round(cast("fire_hydrant:flow_capacity"␣as␣numeric)*60)␣||␣'␣l/min'␣else␣null␣end␣as␣fh_f
    from␣&prefix;_point
    where␣(␣emergency='fire_hydrant'␣or␣amenity='fire_hydrant'␣)
    )␣as␣hydrants
    </Parameter>
    &datasource-settings;
    </Datasource>
    </Layer>
    [...]
    

    Das \n erzeugt laut Dokumentation einen Zeilenumbruch (wie auch in "richtigen" Programmiersprachen). Ich habe es auch schon ohne probiert, aber auch da funktioniert es nicht.

    Wenn ich renderd mit der Option -f starte bekomme ich folgenden Fehler ausgegeben:

    renderd[29494]:␣An␣error␣occurred␣while␣loading␣the␣map␣layer␣'default':␣Failed␣to␣parse␣expression:␣"H[fh_d]"␣in␣TextSymbolizer␣in␣style␣'hydrants'␣in␣map␣'/etc/mapnik-osm-data/osm.xml'
    

    Anscheinend kann ich also bei <TextSymbolizer> nur eine Variable angeben, z.B. [fh_d] (so war es auch in der ursprünglichen OpenFireMap-Datei).

    Kann mir jemand einen Tipp geben wo ich ansetzen muss damit ich die Sache zum Laufen kriege?

    Vielen Dank schonmal,

    Christoph


    • Re: Mapnik: Erzeugen von kombinierter Beschriftung aus mehreren Feldern · wambacher (Gast) · 03.05.2013 20:57 · [flux]

      glaube schon: formuliere deine Abfrage etwa so:

      (select␣way,
      name,
      emergency,
      amenity,
      ref,
      'H'␣||␣coalesce("fire_hydrant:type",'_')␣||␣'\n'␣||
      replace(replace("fire_hydrant:diameter",'fixme','␣'),'FIXME','␣')␣||
      "fire_hydrant:pressure"␣||
      case
      when␣"fire_hydrant:flow_capacity"␣similar␣to␣'[[:digit:]]+'␣then
      round(cast("fire_hydrant:flow_capacity"␣as␣numeric)*60)␣||␣'␣l/min'
      else
      null
      end␣as␣fh_full
      from␣&prefix;_point
      where␣(␣emergency='fire_hydrant'␣or␣amenity='fire_hydrant'␣)
      )␣as␣hydrants;
      
      <TextSymbolizer␣allow-overlap="true"
      fontset-name="bold-fonts"
      size="9"
      fill="#ff0000"
      dy="9"
      halo-radius="1"
      wrap-width="0">
      [fh_full]
      </TextSymbolizer>
      

      Knackpunt ist, dass Postgresql EIN Feld fh_full zurückgibt, das dann im textsymbolizer verwendet wird.
      es könnten noch 1-2 tippfehler drin sein, aber das Prinzip sollte klar sein.

      Gruss
      walter


    • Re: Mapnik: Erzeugen von kombinierter Beschriftung aus mehreren Feldern · cziehr (Gast) · 05.05.2013 16:47 · [flux]

      Hallo Walter,

      vielen Dank schonmal für deine Arbeit!

      Allerdings hab ich jetzt noch das Problem, dass [fh_t] dafür benutzt wurde zu unterscheiden welche Grafik für den jeweiligen Hydranten angezeigt wird (Unterscheidung in der Bauform unterirdisch <-> oberirdisch). Ich dachte dann dass ich einfach beide Stile drinlasse, denn ich wollte in Zoomstufe 17 nur die Bauart und den Durchmesser und in Zoomstufe 18 komplett alles anzeigen lassen. Mein Lösungsansatz

      ␣␣␣<Rule>
      &maxscale_zoom17;
      &minscale_zoom17;
      <Filter>[fh_t]␣=␣'underground'</Filter>
      <PointSymbolizer␣file="&symbols;/hydrant_u_17.png"␣allow-overlap="true"/>
      <TextSymbolizer␣allow-overlap="true"␣fontset-name="bold-fonts"␣size="9"␣fill="#ff0000"␣dy="9"␣halo-radius="1"␣wrap-width="0">[fh_d]</TextSymbolizer>
      </Rule>
      <Rule>
      &maxscale_zoom18;
      &minscale_zoom18;
      <Filter>[fh_t]␣=␣'underground'</Filter>
      <PointSymbolizer␣file="&symbols;/hydrant_u_17.png"␣allow-overlap="true"/>
      <TextSymbolizer␣allow-overlap="true"␣fontset-name="bold-fonts"␣size="9"␣fill="#ff0000"␣dy="9"␣halo-radius="1"␣wrap-width="0">[fh_full]</TextSymbolizer>
      </Rule>
      
      <Layer␣name="hydrants_17"␣status="on"␣srs="&osm2pgsql_projection;">
      <StyleName>hydrants</StyleName>
      <Datasource>
      <Parameter␣name="table">
      (select␣way,name,emergency,amenity,ref,
      coalesce("fire_hydrant:type",'_')␣as␣fh_t,replace(replace("fire_hydrant:diameter",'fixme','␣'),'FIXME','␣')␣as␣fh_d
      from␣&prefix;_point
      where␣(␣emergency='fire_hydrant'␣or␣amenity='fire_hydrant'␣)
      )␣as␣hydrants
      </Parameter>
      &datasource-settings;
      </Datasource>
      </Layer>
      <Layer␣name="hydrants_18"␣status="on"␣srs="&osm2pgsql_projection;">
      <StyleName>hydrants</StyleName>
      <Datasource>
      <Parameter␣name="table">
      (select␣way,
      name,
      emergency,
      amenity,
      ref,
      'H'␣||␣coalesce("fire_hydrant:type",'_')␣||␣'\n'␣||
      replace(replace("fire_hydrant:diameter",'fixme','␣'),'FIXME','␣')␣||
      "fire_hydrant:pressure"␣||
      case
      when␣"fire_hydrant:flow_capacity"␣similar␣to␣'[[:digit:]]+'␣then
      round(cast("fire_hydrant:flow_capacity"␣as␣numeric)*60)␣||␣'␣l/min'
      else
      null
      end␣as␣fh_full
      from␣&prefix;_point
      where␣(␣emergency='fire_hydrant'␣or␣amenity='fire_hydrant'␣)
      )␣as␣hydrants
      </Parameter>
      &datasource-settings;
      </Datasource>
      </Layer>
      

      (es sind noch weitere Regeln vorhanden die eigentlich alle gleich aufgebaut sind, die habe ich aber aufgrund der Übersichtlichkeit ausgeblendet)

      hat dann aber irgendie nicht funktioniert - ich bekomme beim Aufruf von renderd die Fehlermeldung

      ERROR:␣␣column␣"fh_d"␣does␣not␣exist
      LINE␣1:␣SELECT␣AsBinary("way")␣AS␣geom,"fh_d","fh_t"␣from
      ^
      Full␣sql␣was:␣'SELECT␣AsBinary("way")␣AS␣geom,"fh_d","fh_t"␣from
      (select␣way,
      name,
      emergency,
      amenity,
      ref,
      'H'␣||␣coalesce("fire_hydrant:type",'_')␣||␣'\n'␣||
      replace(replace("fire_hydrant:diameter",'fixme','␣'),'FIXME','␣')␣||
      "fire_hydrant:pressure"␣||
      case
      when␣"fire_hydrant:flow_capacity"␣similar␣to␣'[[:digit:]]+'␣then
      round(cast("fire_hydrant:flow_capacity"␣as␣numeric)*60)␣||␣'␣l/min'
      else
      null
      end␣as␣fh_full
      from␣planet_osm_point
      where␣(␣emergency='fire_hydrant'␣or␣amenity='fire_hydrant'␣)
      )␣as␣hydrants
      WHERE␣"way"␣&&␣SetSRID('BOX3D(890185.6314091616␣6364299.849080344,892937.36442743␣6367051.582098612)'::box3d,␣900913)'
      

      Weist du hier vielleicht auch noch einen Rat?

      Viele Grüße und nochmal Danke!

      Christoph


    • Re: Mapnik: Erzeugen von kombinierter Beschriftung aus mehreren Feldern · wambacher (Gast) · 05.05.2013 18:09 · [flux]

      cziehr wrote:

      Weist du hier vielleicht auch noch einen Rat?

      Full␣sql␣was:␣'SELECT␣AsBinary("way")␣AS␣geom,"fh_d","fh_t"␣from
      (select␣way,
      name,
      emergency,
      amenity,
      ref,
      abc␣as␣fh_d,␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣<-------------------␣hier
      xyz␣as␣fh_t,␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣<-------------------␣erweitern
      'H'␣||␣coalesce("fire_hydrant:type",'_')␣||␣'\n'␣||
      replace(replace("fire_hydrant:diameter",'fixme','␣'),'FIXME','␣')␣||
      "fire_hydrant:pressure"␣||
      case
      when␣"fire_hydrant:flow_capacity"␣similar␣to␣'[[:digit:]]+'␣then
      round(cast("fire_hydrant:flow_capacity"␣as␣numeric)*60)␣||␣'␣l/min'
      else
      null
      end␣as␣fh_full
      
      from␣planet_osm_point
      where␣(␣emergency='fire_hydrant'␣or␣amenity='fire_hydrant'␣)
      )␣as␣hydrants
      WHERE␣"way"␣&&␣SetSRID('BOX3D(890185.6314091616␣6364299.849080344,892937.36442743␣6367051.582098612)'::box3d,␣900913)'
      

      jo, etwas unhübsch, aber: hole dir fh_d,fh_t und fh_full von der db ab. abc und xyz natürlich ähnlich wie bei fh_full anpassen.
      irgendwie doppelt gemoppelt aber was besseres fällt mir auf die schnelle auch nicht ein.


    • Re: Mapnik: Erzeugen von kombinierter Beschriftung aus mehreren Feldern · cziehr (Gast) · 05.05.2013 19:11 · [flux]

      Danke für die Antwort. Ich hab noch ein bisschen umgebaut, und jetzt ist es (fast) perfekt:

      <Layer␣name="hydrants"␣status="on"␣srs="&osm2pgsql_projection;">
      <StyleName>hydrants</StyleName>
      <Datasource>
      <Parameter␣name="table">
      (select␣way,
      name,
      emergency,
      amenity,
      ref,
      "fire_hydrant:type"␣as␣fh_t,
      'H'␣||␣replace(replace("fire_hydrant:diameter",'fixme','␣'),'FIXME','␣')␣as␣fh_d,
      'H'␣||␣replace(replace("fire_hydrant:diameter",'fixme','␣'),'FIXME','␣')␣||␣'&#10;'␣||
      floor(cast("fire_hydrant:pressure"␣as␣numeric)*10)*0.1␣||␣'␣bar'␣||␣'&#10;'␣||
      floor(cast("fire_hydrant:flow_capacity"␣as␣numeric)*60*0.01)*100␣||␣'␣l/min'
      as␣fh_full
      from␣&prefix;_point
      where␣(␣emergency='fire_hydrant'␣or␣amenity='fire_hydrant'␣)
      )␣as␣hydrants
      </Parameter>
      &datasource-settings;
      </Datasource>
      </Layer>
      

      als Karte sieht es dann so aus:

      http://ffebg.no-ip.org:911/osm/slippyma … layers=0B0 (rechts oben den Layer "FF Ebg externer Zugriff" wählen, hab nur die Daten für unseren Landkreis und noch etwas Gebiet drumrum auf dem Server da dieser schon etwas älter ist. Also nicht wundern wenn der eigene Ort nicht auf der Karte erscheint)

      Vielen Dank nochmal an wambacher für die schnelle und kompetente Hilfe!

      Zum "(fast) perfekt": Gibt es eine Möglichkeit einer if-else-abfrage? In den ersten Posts hatte ich ja noch einer "when "fire_hydrant:flow_capacity" similar to '[[:digit:]]+' then"-Abfrage drin, aber die funktioniert irgendwie nicht... Ich will einfach nur prüfen ob z.B. der Druck des Hydranten angegeben ist und wenn nicht dann diesen nicht verwenden. Ansonsten wird nämlich nur das Symbol gezeichnet, aber Der Leitungsdurchmesser und die Durchflussrate werden nicht angezeigt, auch wenn diese vorhanden sind und halt nur der Druck nicht.

      Viele Grüße,

      Christoph


    • Re: Mapnik: Erzeugen von kombinierter Beschriftung aus mehreren Feldern · wambacher (Gast) · 05.05.2013 20:06 · [flux]

      cziehr wrote:

      Zum "(fast) perfekt": Gibt es eine Möglichkeit einer if-else-abfrage?

      wenn es um Mapnik geht, muß ich passen. ich "spreche" nur Sql 😉
      in sql gibt es kein if sondern das wird alles mit case erledigt - aber das ist jetzt wohl nicht dein Problem.

      Gruss
      walter

      http://www.postgresql.org/docs/9.1/stat … ional.html


    • Re: Mapnik: Erzeugen von kombinierter Beschriftung aus mehreren Feldern · cziehr (Gast) · 05.05.2013 20:09 · [flux]

      Zeiter Satz aus deinem Link:

      The SQL CASE expression is a generic conditional expression, similar to if/else statements in other programming languages

      Ok, damit wäre das geklärt. Dann muss ich mit CASE experimentieren. Das wird aber gegenüber der vorherigen Probleme die leichteste Übung sein.

      Danke nochmal!


    • Re: Mapnik: Erzeugen von kombinierter Beschriftung aus mehreren Feldern · wambacher (Gast) · 05.05.2013 20:16 · [flux]

      cziehr wrote:

      Danke nochmal!

      Keine Ursache.

      Wie sagten wir früher: "Danksagungen bitte in schriftlicher Form an unseren Chef - Fehlermeldungen und Beschwerden bitte in mündlicher Form an unseren Hausmeister" 😉