Menu

Nie wiem ile osób zna styl OSMapa-Topo Michała Mackiewicza, który można podziwiać między innymi na OSMAPA.PL ale postanowiłem go rozszerzyć o czasy przejść szlaków i przewyższenia. Obecny efekt to:
Obrazek
Teraz kolejno jak tego dokonałem.

1. Po pierwsze potrzebujemy zrobić pewien init. Polega on na dodaniu nowej tabeli z naszymi czasami, oraz brakujących funkcji do postgisa.


CREATE TABLE planet_trails_times (
  id serial,
  dist double precision,
  up double precision,
  up_rev double precision
);

SELECT AddGeometryColumn('planet_trails_times','line',900913,'LINESTRING',2);

CREATE OR REPLACE FUNCTION SUM_BIGGER(double precision[],double precision) RETURNS double precision[] AS $$
DECLARE
    stat ALIAS FOR $1;
    newval ALIAS FOR $2;
    newstat double precision[];
BEGIN
    IF stat[1]<0 THEN
      newstat[1]:=0;
      newstat[2]:=0;
      newstat[3]:=newval;
    ELSE
      IF stat[3]


Te funkcje służą nam do zliczania wysokości dla szlaku, ale o tym później.
2.Następny etap jest nieco bardziej skomplikowany. Polega on na wyciągnięciu z OSM wszystkich relacji dla szlaków turystycznych, następnie wyszukaniu skrzyżowań i pocięciu szlaków za pomocą tych skrzyżowań. Potem następuje UPDATE, który wylicza czas i przewyższenie. Działa on w ten sposób, że liczy poziomice i tutaj do gry wchodzi nowa funkcja agregująca, która zwraca wynik będący przewyższeniem. Np. z danych 100,110,100,120 zwróci 30 i 10, czyli sumowanie w momencie gdy poprzednia jest większa (w dwie strony)

BEGIN TRANSACTION;
-- Clear
TRUNCATE TABLE planet_trails_times;
-- New tmp table with trails and cutting lines.
create temporary table  tmp_trails(type text,line geometry not null) on commit drop;
-- Add trails with type='trail'
INSERT INTO tmp_trails(type,line)
SELECT name, geom FROM (
  SELECT 'trail' as name, (ST_Dump(ST_LineMerge(p.trail))).geom as geom FROM
  (
    SELECT ST_Collect(way) As trail
    FROM planet_osm_rels as relations,planet_osm_line as lines
    WHERE ('hiking' = ANY (relations.tags) OR 'foot' = ANY (relations.tags) )AND 'route' = ANY (relations.tags) AND lines.osm_id = ANY (parts)
    GROUP BY relations.id --LIMIT 10 --remove LIMIT!!!!!!
  ) As p
)As w WHERE ST_Intersects(w.geom,  ST_Transform( CAST('srid=94326;POLYGON((13.03 55.1,13.03 48.39,25.69 48.39,25.69 55.1,13.03 55.1))'::geography AS geometry),900913 ) );
create temporary table  tmp_lines(line geometry not null) on commit drop;
create temporary table  tmp_clines(line geometry not null) on commit drop;
-- Get Diff
INSERT INTO tmp_lines (
  SELECT DISTINCT (ST_Dump(ST_Difference(t1.line,t2.line))).geom AS line  FROM tmp_trails AS t1, tmp_trails AS t2 WHERE ST_Intersects(t1.line,t2.line)
  UNION SELECT line FROM tmp_trails
);
INSERT INTO tmp_clines (
  SELECT DISTINCT (ST_Dump(ST_Difference(trails.line,tCross.crosses))).geom AS line FROM
  ( 
    -- Make multiline
    SELECT ST_Collect(ST_MakeLine(ST_Translate(n.point,0.000001,0.000001), ST_Translate(n.point,-0.000001,-0.000001))) AS crosses FROM
      (
      -- Lines to points
      SELECT DISTINCT ST_StartPoint(t.line) AS point FROM tmp_lines AS t
      UNION
      SELECT DISTINCT ST_EndPoint(t.line) AS point FROM tmp_lines AS t
      ) AS n
    ) AS tCross
  , tmp_trails AS trails WHERE trails.type LIKE 'trail'
);
INSERT INTO planet_trails_times(line)
(
  SELECT DISTINCT r.l FROM
  (
    SELECT line AS l FROM tmp_clines WHERE ST_Length(line)>0.001
  ) AS r
);
COMMIT;
--times
UPDATE planet_trails_times SET dist = f.dist, up=f.up,up_rev = f.up_rev FROM
(
SELECT id, uphill[1] as up,uphill[2] as up_rev,dist FROM
(
  SELECT id,(SUM_AGG(elev)) AS uphill,MAX(dist) AS dist FROM
  (
    SELECT * FROM
    (
      SELECT elev,planet.id,ST_Length(planet.line)*ST_Line_Locate_Point(planet.line,(ST_Dump(ST_Intersection(planet.line,the_geom))).geom) As dist FROM contour,
      (
        SELECT * FROM planet_trails_times
      ) AS planet
      WHERE ST_Intersects(the_geom,planet.line)
    ) As f ORDER BY dist
  ) AS f GROUP BY f.id
) AS f
) As f WHERE planet_trails_times.id=f.id;


3. Ostatnia część to styl do Mapnika


<Layer>
<StyleName>Time_nodes</StyleName>               <Datasource>
        &datasource-settings;     <Parameter name="table">
(                   
SELECT DISTINCT point as way FROM (
SELECT ST_StartPoint(t.line) AS point FROM planet_trails_times AS t      
-- WHERE line ST_Intersects(!bbox!)
UNION               
SELECT ST_EndPoint(t.line) AS point FROM planet_trails_times AS t
-- WHERE line ST_Intersects(!bbox!)     
) As t)As w
</Parameter>
<Parameter name="geometry_field">way</Parameter>
<Parameter name="geometry_table">planet_osm_line</Parameter>       
 </Datasource>
</Layer>            
                    
<Style name="Time_text">
        <Rule>      
                &maxscale_zoom13;   &minscale_zoom17;
<TextSymbolizer name="normal" face_name="DejaVu Sans Book"  halo_fill="#d0ffd0" halo_radius="3"  size="10" fill="#F33" placement="line" dy="15" max_char_angle_delta="50" spacing="1700" min_distance="50" avoid_edges="true" opacity="0.8" minimum-path-length="250" />
       </Rule>      </Style>
                    

<Layer>             
 <StyleName>Time_text</StyleName>
 <Datasource>              <Parameter name="type">postgis</Parameter>
        <Parameter name="dbname">***</Parameter>        <Parameter name="user">***</Parameter>
        <Parameter name="extent">1558472,6257910,2693932,7400780</Parameter>                 
        <Parameter name="table">
(                   
SELECT line as way, ( '←' || to_char(round((up*0.08+dist*15/1000)/5)*5 ,'999D')|| 'min[' ||to_char(up, '9999')||'m]' || '{'|| to_char(dist/1000,'99D9' ) ||'km}' || to_char(round((up_rev*0.08+dist*15/1000)/5)*5 ,'999D')|| 'min[' ||to_char(up_rev, '9999')||'m]' || '→'  ) As normal FROM
(                   
SELECT up,up_rev,dist,ST_Translate(line, ST_X(center)-ST_X(line_center),ST_Y(center)-ST_Y(line_center) ) as line FROM
(                   
SELECT up,up_rev,dist,line,center,ST_Line_Interpolate_Point(line, 0.5) as line_center FROM
(                   
  SELECT ST_MakeLine(ST_StartPoint(line),ST_EndPoint(line)) as line,  ST_Line_Interpolate_Point(line, 0.5) as center,
    (CASE  WHEN up IS NULL THEN 0 WHEN degrees(ST_Azimuth(ST_StartPoint(line), ST_EndPoint(line))) < 180 THEN up_rev ELSE up END) as  up,      
    (CASE  WHEN up_rev IS NULL THEN 0  WHEN degrees(ST_Azimuth(ST_StartPoint(line), ST_EndPoint(line))) < 180 THEN up ELSE up_rev END) as  up_rev,
    dist FROM planet_trails_times WHERE ST_Intersects (line,!bbox!)      
) as f4
) as f3             
) as f2
) as f1             
        </Parameter>
        <Parameter name="geometry_field">way</Parameter>     
        <Parameter name="geometry_table">planet_osm_line</Parameter>
</Datasource>     </Layer>

Pierwsza warstwa to kropki reprezentujące skrzyżowania, druga bardziej skomplikowana to wypisywanie czasów. Główny problem polegał na tym, iż mapnik nie bierze pod uwagę kierunku drogi, a ja oczywiście muszę uwzględnić czy kierunek wypisywania tekstu jest zgodny z kierunkiem linestringa, czy przeciwny.

Styl można obejrzeć Tutaj. Nie jest on w pełni gotowy dlatego mogę go nazwać wersją alpha.

Komentarze:

Dodaj komentarz: