source: subversion/applications/rendering/osmps/osmps.rb @ 15087

Last change on this file since 15087 was 6276, checked in by matthewnc, 12 years ago

osmps - PostScript? Renderer
update to 0.04

  • add ability to set output clipping area (tries not to draw objects outside this area for efficiency, and then PS clips to the area): aiming to more easily allow production of multi-page map booklets etc
  • Property svn:executable set to *
File size: 35.8 KB
Line 
1#! /usr/bin/ruby
2#
3# OSMPS 0.04
4#
5# OpenStreetMap .osm to PostScript renderer
6#
7# Copyright (c) Matthew Newton, 2007
8#
9#-------------------------------------------------------------------------------
10#   This program is free software; you can redistribute it and/or modify
11#   it under the terms of the GNU General Public License as published by
12#   the Free Software Foundation; either version 2 of the License, or
13#   (at your option) any later version.
14#
15#   This program is distributed in the hope that it will be useful,
16#   but WITHOUT ANY WARRANTY; without even the implied warranty of
17#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18#   GNU General Public License for more details.
19#
20#   You should have received a copy of the GNU General Public License
21#   along with this program; if not, write to the Free Software
22#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
23#-------------------------------------------------------------------------------
24#
25#   As an additional exception, PostScript code contained within,
26#   and output by, this program may be freely copied and modified
27#   without restriction.
28#
29#   The PostScript pathtext code is based on Sample Code from the book
30#     "PostScript Language Tutorial and Cookbook"
31#   Copyright (c) Adobe Systems Inc. 1985 and is included in this
32#   software within the terms of the Adobe licence found at
33#   http://partners.adobe.com/public/developer/ps/eula_submit.jsp?eula_name=ps_eula
34#
35#-------------------------------------------------------------------------------
36# This source is best viewed with a folding editor, such as Vim ;-)
37
38require 'xml/libxml'
39
40PSResource = <<EOR# {{{
41%%BeginResource: osmps
42/bd {bind def} bind def
43/pathisrtol
44%  { counttomark 1 sub index
45%    2 index gt
46  { false
47  } def
48/area { dup exec eofill } def
49/line { dup exec stroke } def
50/cline { dup exec closepath stroke } def
51/c {
52255 div 3 1 roll
53255 div 3 1 roll
54255 div 3 1 roll
55setrgbcolor
56} def
57/m { exch x exch y moveto } def
58/l { exch x exch y lineto } def
59/np {newpath} bd
60/st {stroke} bd
61/lw {setlinewidth} bd
62/gs {gsave} bd
63/gr {grestore} bd
64/cpf {closepath fill} bd
65/rgb {setrgbcolor} bd
66
67/osm {/OsmPsMapSymbol findfont 2 scalefont setfont} bd
68
69%------------------------------------------------------------
70% Tweaked PathText code from Adobe PostScript Cookbook
71/pathtextdict 26 dict def
72/pathtext
73  { pathtextdict begin
74  /charbaseoffset 0.15 def
75  /offset exch def
76  /str exch def
77  /pathdist 0 def
78  /setdist offset def
79  /charcount 0 def
80  gsave
81    flattenpath
82    {movetoproc}  {linetoproc}
83    {curvetoproc} {closepathproc}
84    pathforall
85  grestore
86  newpath
87  end
88  } def
89 
90pathtextdict begin
91/movetoproc
92  { /newy exch def /newx exch def
93  /firstx newx def /firsty newy def
94  %/ovr 0 def   <- bug in Adobe's original code
95  /ovr offset def
96  newx newy transform
97  /cpy exch def /cpx exch def
98  } def
99 
100/linetoproc
101  { /oldx newx def /oldy newy def
102  /newy exch def /newx exch def
103  /dx newx oldx sub def
104  /dy newy oldy sub def
105  /dist dx dup mul dy dup mul add sqrt def
106  dist 0 ne
107    { /dsx dx dist div ovr mul def
108      /dsy dy dist div ovr mul def
109      oldx dsx add oldy dsy add transform
110      /cpy exch def /cpx exch def
111      /pathdist pathdist dist add def
112    { setdist pathdist le
113      { charcount str length lt
114      {setchar} {exit} ifelse }
115      { /ovr setdist pathdist sub def
116      exit }
117      ifelse
118    } loop
119      } if
120  } def
121 
122/curvetoproc
123  { (ERROR: No curveto's after flattenpath!) print
124  } def
125 
126/closepathproc
127  { firstx firsty linetoproc
128  firstx firsty movetoproc
129  } def
130 
131/setchar
132  { /char str charcount 1 getinterval def
133  /charcount charcount 1 add def
134  /charwidth char stringwidth pop def
135  gsave
136    cpx cpy itransform translate
137    dy dx atan rotate
138    0 charbaseoffset neg moveto
139    char show
140    0 charbaseoffset rmoveto
141    currentpoint transform
142    /cpy exch def /cpx exch def
143  grestore
144  /setdist setdist charwidth add def
145  } def
146end
147% End of code derived from Adobe source
148%------------------------------------------------------------
149
150%------------------------------------------------------------
151% Calculate the length of the current graphics path
152% - pathlen <length>
153%
154/pathlendict 7 dict def
155/pathlen
156  { pathlendict begin
157  /length 0 def
158  gsave
159    flattenpath
160    {pathlenmt} {pathlenlt}
161    {pathlenct} {pathlencp}
162    pathforall
163  grestore
164  newpath
165  length
166  end
167  } def
168
169pathlendict begin
170/pathlenmt
171  { /newy exch def
172    /newx exch def
173    /firstx newx def
174    /firsty newy def
175  } def
176
177/pathlenlt
178  { /oldx newx def
179    /oldy newy def
180    /newy exch def
181    /newx exch def
182    /length newx oldx sub dup mul
183            newy oldy sub dup mul
184            add sqrt
185            length add def
186  } def
187
188/pathlenct
189  { (This should never happen!) print
190  } def
191
192/pathlencp
193  { firstx firsty pathlenlt
194  } def
195end
196
197%------------------------------------------------------------
198% Draw in a road name, central to the given path, but only
199% if it will actually fit.
200% mark <x1> <y1> <x2> <y2> <xn> <yn> (text) roadname -
201%
202/roadnamedict 3 dict def
203/roadname
204  { roadnamedict begin
205    /text exch def
206    dup exec
207    pathisrtol
208      { reversepath }
209      if
210    gsave
211    /plen pathlen def
212    RoadNameCoreFont
213    /tlen text stringwidth pop def
214    grestore
215    tlen 0.0 gt plen 0.0 gt and
216    plen tlen gt and
217    { gsave
218      1 1 1 setrgbcolor
219      RoadNameOutlineFont
220      text
221      plen 2 div tlen 2 div sub
222      pathtext
223      grestore
224      gsave
225      0 0 0 setrgbcolor
226      RoadNameCoreFont
227      text
228      plen 2 div tlen 2 div sub
229      pathtext
230      grestore
231    } if
232    end
233  } def
234
235/RoadNameFont
236  { /Helvetica-Bold findfont
237  } def
238
239/RoadNameOutline
240RoadNameFont
241dup maxlength 1 add
242exch /UniqueID known not { 1 add } if
243dict def
244
245RoadNameFont
246{ exch dup /FID ne
247  { exch RoadNameOutline 3 1 roll put }
248  { pop pop }
249  ifelse
250} forall
251
252RoadNameOutline
253dup /PaintType 2 put
254dup /StrokeWidth 300 put
255dup /FontName /RoadNameOutline put
256dup /UniqueID 1001 put
257/RoadNameOutline exch definefont pop
258
259/RoadNameCoreFont
260  { RoadNameFont
261    0.5 scalefont
262    setfont
263  } def
264
265/RoadNameOutlineFont
266  { /RoadNameOutline findfont
267    0.5 scalefont
268    setfont
269  } def
270
271RoadNameCoreFont
272
273%%EndResource
274EOR
275# }}}
276PSSymbols = <<EOR# {{{
277%!PS-Adobe-2.0 EPSF-1.0
278%%Creator: Matthew Newton
279%%BoundingBox: -100 -100 100 100
280%%EndComments
281
282%!PS-AdobeFont-1.0: OsmPsMapSymbol 001.000
283%%Title: OsmPsMapSymbol
284%Version: 001.000
285%%CreationDate: Thu Mar 29 23:20:54 2007
286%%Creator: Matthew Newton
287%Copyright: Copyright (c) Matthew Newton
288% 2007-3-29: Created.
289% Generated by FontForge 20061019 (http://fontforge.sf.net/)
290%%EndComments
291
292FontDirectory/OsmPsMapSymbol known{/OsmPsMapSymbol findfont dup/UniqueID known{dup
293/UniqueID get 4167772 eq exch/FontType get 1 eq and}{pop false}ifelse
294{save true}{false}ifelse}{false}ifelse
29512 dict begin
296/FontType 1 def
297/FontMatrix [0.001 0 0 0.001 0 0 ]readonly def
298/FontName /OsmPsMapSymbol def
299/FontBBox {-500 -500 500 500 }readonly def
300/UniqueID 4167772 def
301/XUID [1021 864 700174176 11540681] def
302/PaintType 0 def
303/FontInfo 9 dict dup begin
304 /version (001.000) readonly def
305 /Notice (Copyright \050c\051 Matthew Newton) readonly def
306 /FullName (OsmPsMapSymbol) readonly def
307 /FamilyName (OsmPsMapSymbol) readonly def
308 /Weight (Medium) readonly def
309 /FSType 8 def
310 /ItalicAngle 0 def
311 /isFixedPitch false def
312 /ascent 500 def
313end readonly def
314/Encoding StandardEncoding def
315currentdict end
316currentfile eexec
31704BFDF59CBE545B9A7608E6A873EAB8F48A2C998996D3FA67E4DE5DDC64DE4B43314CF7D
31825A137EC0083CA76D4B52E9651F685281A6DF824636C77DA0B9290F4CAE31C715150BA63
319E06D2369BE0F51247BDD07129098BB78A6E98EEACB698CD9D0BB72DBE44936E90A0B8069
3202B5896AEE49690958D5D7D00686686EFAC9389B34735B8BA85CD441E9EC6938189E46EB3
321FB609C3E875554A4C6970883D6781AC293F8AD67A57BF3924F25A9CB361650FA58A24A2F
322AC68E8B5BFE6AF15C9B99F61247D80963F0B2CA7DC82FA9D98C5D3CF107ED227F790A574
32336727FAA010F747AC51F0EB179AC1DE05CE8578FFC8ED7C9C5D53FF32EFC9C690B2FD051
324097624227ABB5828661664792AD58C3FB49221E4A3E5BCF11BF53C550CD92C321D9B4595
32502D52D7B434A6999B023E4E1F18F9D877ADA8857219C8EDE281739A3BD252841D858008F
32650ABBE70ACD9391A5F9F4FEFB2C3C5B80F746F7BBB9600BBCC7BCE37DA027AB722D0F3FC
32773A15A18C1BA49B808527520A6000F7D01B8CDF722B6F0CDBCF05E89B70193F5778912B4
328AD9F8F0A80A9C0B004D77B7C76E30C2ABDAE5B7AA7A01C370B48032FF6DC827944CB20B1
32956AE567C8E36868886A89A68948D7654117DD38F1293ED6967B217AB76D618A41BA7794C
330FB2504AFB726D1584C42D32C33C32A227A69BDFDEE582BC601E5E686C8CA053A9C79A095
331DEAAF8147384F830BA3D48E448BF35746BEF6F7458C56E943FDB4714C4BC7A0AEC2B4C9C
332290A40FD87C519F0ACA392C9F64F5F7A623967D7448E749BD16E0C4D91CBE617B1291FEC
333503198CA595773A17007A1A47BB1EA0158688D7011265B7535D84F0C6920F1630955638F
3345AA801D589668AE9BF1E6922CD77DD1672E5BC0D69014E2220AB69C99D23D661B2D5C242
33523C15B580D66016AE416168B429D2445EAB59E2D89AEFA486A787C58D1F67A824C9F8CA1
3369D401CAF26C58CA2F7B7B046ACEA410B74D5E6EA82BA53FCFE119FD47DA511CAEAE51569
337577C51EDF2BCA368D24A7C61E74965F320CD3E44994F3687E2FF5CF37462CCBB48AA7CE1
338A9FC64520A15988BB6A2FE0A9C69F79DC85657B7F5D457266DF1B8FF50FCDDEA2036FFC4
339421D9CDE30A3BDE904E1C0F8624913C79B91C47C8D3F78C118F23B88F7615008EA643CEB
340E43B2C347E6568D8CAAD5304B355F30C0F9C9A75DB32BAC455BF8775C27AEA6C73EED3EB
3412F8DB5E3B70495047870D57DEE2CE1EE6C921D43AD56BA6B5B915CA1BE152A80E2831F1F
342067DBA58A0A46A7AE93A723618BBD0D164DFA85C53DC83E94177EB2A3418B1255FB07C91
3435411AFA72242A099D69EFA0A822BC6ED58AEB83B72CB902DEE4E13EA2313764F0981CA3A
344B0C89468B926E84BADE4B196DE9E61C4DDD729BF3CADEE9AC541E9C6F0A9D6EEE0ECB02A
3456E2461B66D86C8404DA6DA6BB1C61ABF0183C9FDCE63C76DED96F2F8FB66DAFA526D86AC
3463A23F613E6B46F1FDF7A9B8F6983C2FCE7AFE2584E681C948F07E82C8FEE27C26F057060
3473B1A79522D71D391BC195C0B9D7BE7D63CE0E943C4A42063E80317B8AF450B85397BC85B
3485E2A9FF6FB979AAF46AA343CE145A2B66ED0F6CCB7C8F4AA670BD4F3192F2744922AF1A8
349C75035063C42685953EDED2589FC2D3249BA6A84E64AADABC7F43B75434A137D99BEF151
350E46F87CCDF7FB15A53306C379281E453D8BEB8C7CAC16C877C06843D0213FF05368BF39E
3510B909CA3C0CA03B501E59EF3BF3BD159D01BF43DFBECDB3D293FAC49739661F030F04518
3525F4F0A4B88B2ED20AEABC8889DB0776905D13FBF1EAFB61B7D1A1CED03D5E4A2FA4E18FB
35372B1E322F30047FEB3A7F66F3C3F9B02B2A4844BFFB29AA230EE6C486BEC852B6ECA992B
3546D7C75BA1E9D47D88BE8C4D20BA775775D9A49F964C853D4147B4A6C1281594189D8EDC7
355DEFF26A600CB3F676CBB528C8F9E589A701707A6896A6A192325FAC205BE45F4A4972826
3565B4C046F941D3E73A72B267AD612000A564ADF56A2F19F1F8F5E379F4A5B6DDDEF98BA91
3570339323A7630152B134146A2523CF46A402100F21833401361DDA5DA0401D457F7F36EC4
3588FA3B70A4F149F567F8B979742E9A09F976B5F4F09CCCAE5F024FDD7D388C033FBE8386C
359223F07C7F595BC550280A7FDBACBCD1A7C1ABD4354F21B75CAB3AC4A4BDCAA5C8F89549B
360EDD03CBBF85BFE6575516F4A4D692BA520AAAA998B74A224A29AC0B6113ACECC88D6DA74
3615C23715D684CE9A8C90C5C0E5820E2F48680D98A98FFB02CD134023C6771C5316CDE6D23
362CAE1B1B69FD2DF7CBC07BBF43C92F40D5CE76E9D0A4990C79A889EE6670FEC948F771438
3635E9FA212CCB24047C5843E60328DA0AD4493419CDF61C65D384E2ABCD716F4B86DCF1FD0
364BA8EEAC34A039128E6FD5F3DD2B0A5E43531A4B18D2F867157E61971C34901C04DB41D09
36522B9350781A729A646825F7DE1A15DD2A2F20214C0FEA3DACCBBC99602843F8CE05C372E
366AE4216B4E3B354C393216A36CFC28B7AFF671AF0EE2D701329216FA203C944810CC303FE
367153ED1EC7266903C3176B8ECEB7069C98074B54368E6D321DDA11B4D47649892369BEEFC
3685AD6B875B8B4DA42130FA02583A12D899C3BBCFA71C4328AD6CA498EAE7A85D67FB52574
3696E27C9DE7589D165583A3412924256D02CC043ECFBB53BCCA7729B5BC8D23053FCE18114
370A88C8D237EE4EF0122027C9098A278C632885B53B669DE68E060415BDEB20F0AC1CA61ED
37122E353323AF1FED55916ABED28F0775AE4237A827A944C8B3CEEBE688B011BC69E697209
3723AF24A74E0DF65A155A6885EE2A46996E6CB1F35608AFC257135B3D3AA50BF420AD6169E
373CAA113F785
3740000000000000000000000000000000000000000000000000000000000000000
3750000000000000000000000000000000000000000000000000000000000000000
3760000000000000000000000000000000000000000000000000000000000000000
3770000000000000000000000000000000000000000000000000000000000000000
3780000000000000000000000000000000000000000000000000000000000000000
3790000000000000000000000000000000000000000000000000000000000000000
3800000000000000000000000000000000000000000000000000000000000000000
3810000000000000000000000000000000000000000000000000000000000000000
382cleartomark
383{restore}if
384
385%%BeginDocument: osmlogos.eps
386/logo-churchofe {
387  gs osm
388  {0.3 setgray} if
389  (c) show
390  gr
391} def
392/logo-church {
393  gs osm
394  pop
395  (C) show
396  gr
397} def
398/logo-pub {
399  gs osm
400  (B) show
401  {0.8 0.5 0 rgb
402  (b) show} if
403  gr
404} def
405/logo-hospital {
406  gs osm
407  {0.8 0 0 rgb} if
408  (H) show
409  gr
410} def
411/logo-postoffice {
412  gs osm
413  dup {0.8 0.2 0 rgb} if
414  (P) show
415  {0.8 0.8 0 rgb
416  (p) show} if
417  gr
418} def
419/logo-parking {
420  gs osm
421  {0.3 0.3 0.9 rgb} if
422  (k) show
423  gr
424} def
425/logo-library {
426  gs osm
427  pop
428  (l) show
429  gr
430} def
431%%EndDocument
432%%EOF
433EOR
434# }}}
435class Style# {{{
436  def initialize# {{{
437    @match = {}
438    @style = ""
439    @type = :path
440    @drawps = {}
441  end
442
443# }}}
444  def addtag(k, va)# {{{
445    if va == nil
446      @match[k] = nil
447    end
448    if not @match.has_key?(k)
449      @match[k] = []
450    end
451    if @match[k] != nil
452      arr = va
453      if va.class == String
454        arr = [va]
455      end
456      arr.each do |v|
457        @match[k].push(v)
458      end
459    end
460  end
461
462# }}}
463  def matchtags(tags)# {{{
464    @match.keys.each do |m|
465      if not tags.has_key?(m)
466        return false
467      end
468      if @match[m] != nil
469        if not @match[m].include?(tags[m])
470          return false
471        end
472      end
473    end
474    true
475  end
476
477# }}}
478  def settype(type)# {{{
479    if [:area, :path, :node, :any].include?(type)
480      @type = type
481    else
482      raise "bad type"
483    end
484  end
485
486# }}}
487  def type# {{{
488    @type
489  end
490
491# }}}
492  def area?# {{{
493    @type == :area
494  end
495
496# }}}
497  def path?# {{{
498    @type == :path
499  end
500
501# }}}
502  def node?# {{{
503    @type == :node
504  end
505
506# }}}
507  def adddrawps(layer, ps)# {{{
508    if not @drawps.has_key?(layer)
509      @drawps[layer] = []
510    end
511    @drawps[layer].push(ps)
512  end
513 
514# }}}
515  def adddrawtagstring(layer, tagname)# {{{
516    if not @drawps.has_key?(layer)
517      @drawps[layer] = []
518    end
519    @drawps[layer].push("%tag #{tagname}")
520  end
521 
522# }}}
523  def layers# {{{
524    @drawps.keys
525  end
526 
527# }}}
528  def length# {{{
529    @drawps.length
530  end
531
532# }}}
533  def ps(layer, tags)# {{{
534  # return "" if layer is out of range
535    if @drawps[layer] == nil
536      return ""
537    end
538    ps = ""
539    @drawps[layer].each do |d|
540      s = d
541      if d[0].chr == "%"
542        cmd = d.split(" ")
543        if cmd[0] == "%tag"
544          s = tags.has_key?(cmd[1]) ? "(#{tags[cmd[1]]})" : "()"
545        end
546      end
547      ps += s + "\n"
548    end
549#    @drawps[num].join(" ") + "\n"
550    ps
551  end
552
553# }}}
554  def to_s# {{{
555    @drawps.join(" ") + "\n"
556  end
557
558# }}}
559end #}}}
560class Tags #{{{
561  def initialize(tags)# {{{
562    @tags = {}
563    self.append(tags)
564    @usecount = 0
565    @styles = nil
566    @styletypes = {}
567  end
568
569# }}}
570  def append(tags)# {{{
571    tags.keys.each do |t|
572      @tags[t] = tags[t]
573    end
574  end
575
576# }}}
577  def tags# {{{
578    @tags
579  end
580
581# }}}
582  def length# {{{
583    @tags.length
584  end
585
586# }}}
587  def styles# {{{
588    @styles
589  end
590
591# }}}
592  def styletypes# {{{
593    @styletypes.keys
594  end
595
596# }}}
597  def renderprepare(styles)# {{{
598    @styles = []
599    styles.each do |s|
600      if s.matchtags(@tags)
601        @styles.push(s)
602        @styletypes[s.type] = 1
603      end
604    end
605  end
606
607# }}}
608  def renderclear# {{{
609    @styles = nil
610  end
611
612# }}}
613  def renderpre# {{{
614    "gs\n"
615  end
616
617# }}}
618  def render# {{{
619    ps = ""
620    @styles.each do |s|
621      ps += s.to_s
622    end
623    ps
624  end
625
626# }}}
627  def renderlayers# {{{
628    layers = {}
629    @styles.each do |s|
630      s.layers.each do |l|
631        layers[l] = 1
632      end
633    end
634    layers.keys
635  end
636
637# }}}
638  def renderlayer(l)# {{{
639    ps = ""
640    @styles.each do |s|
641      ps += s.ps(l, @tags)
642    end
643    ps
644  end
645
646# }}}
647  def renderpost# {{{
648    "gr\n"
649  end
650
651# }}}
652  def renderlength# {{{
653    length = 0
654    @styles.each { |s| length = length > s.length ? length : s.length }
655    length
656  end
657
658# }}}
659  def inc# {{{
660    @usecount += 1
661  end
662
663# }}}
664  def dec# {{{
665    @usecount -= 1
666  end
667
668# }}}
669  def used# {{{
670    @usecount
671  end
672
673# }}}
674  def to_s# {{{
675    "tags(" + @tags.map{|t| t[0]+"="+t[1]}.join(",") + ")"
676  end
677
678# }}}
679end #}}}
680class BBox #{{{
681  attr_reader :minx, :miny, :maxx, :maxy
682
683  def initialize(x1 = nil, y1 = nil, x2 = nil, y2 = nil)# {{{
684    @minx = nil
685    @maxx = nil
686    @miny = nil
687    @maxy = nil
688
689    if x1 and y1 and x2 and y2
690      set(x1, y1, x2, y2)
691    end
692  end
693
694# }}}
695  def set(x1, y1, x2, y2)# {{{
696  # error here if any params are nil...
697    #puts "set: #{x1}  #{y1}  #{x2}  #{y2}"
698    if x1 < x2
699      @minx = x1
700      @maxx = x2
701    else
702      @minx = x2
703      @maxx = x1
704    end
705
706    if y1 < y2
707      @miny = y1
708      @maxy = y2
709    else
710      @miny = y2
711      @maxy = y1
712    end
713  end
714
715# }}}
716  def get# {{{
717    {:minx => @minx, :miny => @miny, 
718     :maxx => @maxx, :maxy => @maxy}
719  end
720
721# }}}
722  def width# {{{
723    @maxx - @minx
724  end
725
726# }}}
727  def height# {{{
728    @maxy - @miny
729  end
730
731# }}}
732  def expand(x, y)# {{{
733  # expand the bbox to include the point (x,y)
734    #puts "expand: #{x}  #{y}"
735    #puts to_s
736    if x < @minx
737      @minx = x
738    end
739
740    if x > @maxx
741      @maxx = x
742    end
743
744    if y < @miny
745      @miny = y
746    end
747
748    if y > @maxy
749      @maxy = y
750    end
751  end
752
753# }}}
754  def merge(bb)# {{{
755    if bb.minx > @minx
756      @minx = bb.minx
757    end
758
759    if bb.maxx > @maxx
760      @maxx = bb.maxx
761    end
762
763    if bb.miny > @miny
764      @miny = bb.miny
765    end
766
767    if bb.maxy > @maxy
768      @maxy = bb.maxy
769    end
770  end
771
772# }}}
773  def overlaps(bb)# {{{
774  # return true if bb overlaps self
775
776    if bb.maxx <= @minx
777      return false
778    end
779
780    if bb.minx >= @maxx
781      return false
782    end
783
784    if bb.maxy <= @miny
785      return false
786    end
787
788    if bb.miny >= @maxy
789      return false
790    end
791
792    true
793  end
794
795# }}}
796  def to_s# {{{
797    "(#{@minx}, #{@miny}), (#{@maxx}, #{@maxy})"
798  end
799
800# }}}
801end #}}}
802class Mercator#{{{
803  def self.to_x(lon)# {{{
804    (lon + 180) / 360
805  end
806
807  # }}}
808  def self.to_y(lat)# {{{
809    ly = self.projf(85.0511)
810    y = self.projf(lat)
811    (ly - y) / (2 * ly)
812  end
813
814  # }}}
815
816  private
817
818  def self.projf(la)# {{{
819    la = la * (3.1415926535897932384/180)
820    Math.log10(Math.tan(la) + (1/Math.cos(la)))
821  end
822
823# }}}
824end #}}}
825class MapObject #{{{
826  def initialize# {{{
827    @tags = nil
828    @graph = nil
829    @osmid = nil
830  end
831
832# }}}
833  def setgraph(g)# {{{
834    if @graph != nil
835      raise "error"
836    end
837    @graph = g
838  end
839
840# }}}
841  def settags(t)# {{{
842    @tags = t
843  end
844
845# }}}
846  def setosmid(id)# {{{
847    @osmid = id.to_i
848  end
849
850# }}}
851  def osmid# {{{
852    @osmid
853  end
854
855# }}}
856  def addtags(t)# {{{
857    if @tags == nil
858      return settags(t)
859    end
860    if @graph != nil
861      return @graph.addtags(self, t)
862    end
863    @tags = @tags + t
864  end
865
866# }}}
867  def tags# {{{
868    @tags
869  end
870
871# }}}
872end #}}}
873class Node < MapObject #{{{
874  attr_reader :lon, :lat
875
876  def initialize(lon, lat)# {{{
877    @lon = lon.to_f
878    @lat = lat.to_f
879    super()
880  end
881
882  # }}}
883  def x# {{{
884    Projection.to_x(@lon)
885  end
886
887  # }}}
888  def y# {{{
889    Projection.to_y(@lat)
890  end
891
892  # }}}
893  def to_s# {{{
894    #"node(" + @lon.to_s + "," + @lat.to_s + ")"
895    "node(#" + @osmid.to_s + ")"
896  end
897 
898  # }}}
899end #}}}
900class Path < MapObject# {{{
901  def initialize(nodelist)# {{{
902    super()
903    @nodelist = nodelist
904    @closed = false
905    if nodelist[0] == nodelist[-1]
906      @closed = true
907    end
908    @bbox = nil
909  end
910
911# }}}
912  def closed?# {{{
913    @closed
914  end
915
916# }}}
917  def setopen# {{{
918    @closed = false
919  end
920
921# }}}
922  def setclosed# {{{
923    @closed = true
924  end
925
926# }}}
927  def split(snode)# {{{
928    if @closed
929      raise :closedcantsplit
930    end
931    if snode == @nodelist[0] or snode == @nodelist[-1]
932      raise :atendcantsplit
933    end
934    position = @nodelist.index(snode)
935    if position == nil
936      raise :nonodetosplit
937    end
938  end
939
940# }}}
941  def rendercount# {{{
942    2
943  end
944
945  # }}}
946  def render# {{{
947    ps = ""
948    @tags.renderlayers.sort.each do |l|
949      ps += renderlayer(l)
950    end
951    ps
952  end
953
954  # }}}
955  def renderlayer(l)# {{{
956    tr = @tags.renderlayer(l)
957    if tr == ""
958      return ""
959    end
960    ps = "{ np "
961    ps += pspath()
962    ps += "} "
963    ps += tr
964    ps += "pop\n"
965    ps
966  end
967
968  # }}}
969  def pspath# {{{
970    ps = "#{@nodelist[0].x} #{@nodelist[0].y} m\n"
971    stop = @nodelist.length-1
972    if @closed and @nodelist[0] == @nodelist[stop]
973      stop -= 1
974    end
975    for n in (1..stop)
976      ps += "#{@nodelist[n].x} #{@nodelist[n].y} l\n"
977    end
978    if @closed
979      ps += "closepath\n"
980    end
981    ps
982  end
983
984  # }}}
985  def bbox# {{{
986    if !@bbox
987      @bbox = BBox.new(@nodelist[0].x, @nodelist[0].y,
988                   @nodelist[0].x, @nodelist[0].y)
989
990      @nodelist.each do |n|
991        @bbox.expand(n.x, n.y)
992      end
993    end
994
995    @bbox
996  end
997
998  # }}}
999  def inbbox?(checkbb)# {{{
1000  # why "not"???
1001    !checkbb.overlaps(bbox)
1002  end
1003
1004  # }}}
1005  def to_s# {{{
1006    "path(#" + @osmid.to_s + ")"
1007  end
1008
1009  # }}}
1010end # }}}
1011class Area < MapObject# {{{
1012  attr_reader :bbox
1013
1014  def initialize(path)# {{{
1015    super()
1016    @paths = []
1017    @tags = nil
1018    if path != nil
1019      @paths = [path]
1020      @bbox = path.bbox
1021      @tags = path.tags
1022    else
1023      @bbox = BBox.new
1024    end
1025  end
1026
1027# }}}
1028  def addpath(path)# {{{
1029    if @tags == nil
1030      @tags = path.tags
1031    end
1032    if @tags != path.tags
1033      raise "all paths in an area must have the same tags"
1034    end
1035    @paths.push(path)
1036    @bbox.merge(path.bbox)
1037  end
1038
1039  # }}}
1040  def render# {{{
1041    ps = ""
1042    @tags.renderlayers.sort.each do |l|
1043      ps += renderlayer(l)
1044    end
1045    ps
1046  end
1047
1048  # }}}
1049  def renderlayer(l)# {{{
1050    tr = @tags.renderlayer(l)
1051    if tr == ""
1052      return ""
1053    end
1054    ps = "{ np "
1055    @paths.each do |p|
1056      ps += p.pspath
1057    end
1058    ps += "} "
1059    ps += tr
1060    ps += "pop\n"
1061    ps
1062  end
1063
1064  # }}}
1065  def inbbox?(checkbb)# {{{
1066  # why "not"???
1067    !checkbb.overlaps(bbox)
1068  end
1069
1070  # }}}
1071end # }}}
1072class Graph#{{{
1073  attr_reader :lonlatbbox
1074
1075  def initialize# {{{
1076    @nodes = {}
1077    @paths = {}
1078    @areas = {}
1079    @tags = {}
1080    @styles = []
1081    @scale = 1000000
1082    @clipbbox = nil
1083
1084    @lonlatbbox = BBox.new
1085  end
1086 
1087  # }}}
1088  def importosm(file) #{{{
1089    # open xml document
1090    doc = XML::Document.file(file)
1091    root = doc.root
1092
1093
1094    # hash to keep track of osm ids
1095    nodes = {}
1096    # read nodes
1097    doc.find("//osm/node").each do |n|
1098      if n['visible'] != 'true'
1099        next
1100      end
1101      tags = {}
1102      n.each_child do |c|
1103        if c.name == "tag" and c['k'] != "created_by"
1104          tags[c['k']] = c['v']
1105        end
1106      end
1107      if n['action'] != 'delete'
1108        node = Node.new(n['lon'], n['lat'])
1109        node.settags(Tags.new(tags))
1110        node.setosmid(n['id'])
1111        addnode(node)
1112        nodes[n['id']] = node
1113      end
1114    end
1115
1116    ways = {}
1117    # pull in all the ways
1118    doc.find("//osm/way").each do |w|
1119      tags = {}
1120      waynodes = []
1121      if w['action'] == 'delete' or w['visible'] != 'true'
1122        next
1123      end
1124      w.each_child do |c|
1125        if c.name == "tag" and c['k'] != "created_by"
1126          tags[c['k']] = c['v']
1127        end
1128        if c.name == "nd"
1129          # add node to nodes list only if it existed in the osm file
1130          if nodes.has_key?(c['ref'])
1131            waynodes.push(nodes[c['ref']])
1132          end
1133        end
1134      end
1135
1136      p = Path.new(waynodes)
1137      p.settags(Tags.new(tags))
1138      p.setosmid(w['id'])
1139      addpath(p)
1140      ways[w['id']] = p
1141
1142      if p.closed?
1143        addarea(Area.new(p))
1144      end
1145    end
1146
1147    if nodes.length > 0
1148      @lonlatbbox.set(nodes[nodes.keys[0]].lon, nodes[nodes.keys[0]].lat,
1149                      nodes[nodes.keys[0]].lon, nodes[nodes.keys[0]].lat)
1150      nodes.keys.each do |n|
1151        @lonlatbbox.expand(nodes[n].lon, nodes[n].lat)
1152      end
1153    end
1154  end #}}}
1155  def addnode(node)# {{{
1156    node.setgraph(self)
1157    @nodes[node] = {}
1158    # this call will use findtags to make sure that duplicate tags
1159    # are stored in the same Tag object
1160    setobjtags(node, node.tags)
1161  end
1162 
1163  # }}}
1164  def addpath(path)# {{{
1165    path.setgraph(self)
1166    @paths[path] = 1
1167    setobjtags(path, path.tags)
1168  end
1169 
1170  # }}}
1171  def addarea(area)# {{{
1172    area.setgraph(self)
1173    @areas[area] = 1
1174  end
1175 
1176  # }}}
1177  def addstyle(style)# {{{
1178    @styles.push(style)
1179  end
1180 
1181  # }}}
1182  def nodes# {{{
1183    @nodes.keys
1184  end
1185 
1186  # }}}
1187  def tags# {{{
1188    @tags
1189  end
1190 
1191  # }}}
1192  def addtags(obj, tags)# {{{
1193    if tags == nil
1194      return
1195    end
1196    if obj.tags == nil
1197      newtags = tags
1198    else
1199      newtags = obj.tags.tags.merge(tags)
1200    end
1201    setobjtags(obj, newtags)
1202  end
1203 
1204  # }}}
1205  def findtags(ftags)# {{{
1206    @tags.keys.each do |t|
1207      if t.tags == ftags.tags
1208        return t
1209      end
1210    end
1211    nil
1212  end
1213 
1214  # }}}
1215  def setobjtags(obj, tags)# {{{
1216    tagdec(obj.tags)
1217    t = findtags(tags)
1218    if t == nil
1219      t = tags
1220    end
1221    obj.settags(t)
1222    taginc(t)
1223  end
1224 
1225  # }}}
1226  def setclip(lon1, lat1, lon2, lat2)# {{{
1227    @clipbbox = BBox.new(Projection.to_x(lon1), Projection.to_y(lat1),
1228                         Projection.to_x(lon2), Projection.to_y(lat2))
1229  end
1230 
1231  # }}}
1232  def clearclip#{{{
1233    @clipbbox = nil
1234  end
1235 
1236  # }}}
1237  def to_s# {{{
1238    str = "== nodes ==\n"
1239    @nodes.keys.each do |n|
1240      str += "#{n} "
1241      str += "#{n.tags}\n"
1242    end
1243
1244    str += "== paths ==\n"
1245    @paths.keys.each do |p|
1246      str += "#{p} "
1247      str += "#{p.tags}\n"
1248    end
1249
1250    str += "== tags ==\n"
1251    @tags.keys.each do |t|
1252      str += "#{t.to_s}\n"
1253    end
1254    str
1255  end
1256 
1257  # }}}
1258  def bbox# {{{
1259    mm = {}
1260    mm[:miny] = mm[:maxy] = @nodes.keys[0].y
1261    mm[:minx] = mm[:maxx] = @nodes.keys[0].x
1262
1263    @nodes.keys.each do |n|
1264      if n.y <  mm[:miny]
1265        mm[:miny] = n.y
1266      end
1267      if n.x < mm[:minx]
1268        mm[:minx] = n.x
1269      end
1270      if n.y >  mm[:maxy]
1271        mm[:maxy] = n.y
1272      end
1273      if n.x > mm[:maxx]
1274        mm[:maxx] = n.x
1275      end
1276    end
1277
1278    BBox.new(mm[:minx], mm[:miny], mm[:maxx], mm[:maxy])
1279#    mm
1280  end
1281
1282  #}}}
1283  def epsbbox(mm, userscale = 1)# {{{
1284    r = {}
1285    r[:width] = (mm.maxx - mm.minx) * @scale * userscale
1286    r[:height] = (mm.maxy - mm.miny) * @scale * userscale
1287    r[:nodeminmax] = mm.get
1288    r
1289  end
1290
1291  # }}}
1292  def eps(userscale = 1)# {{{
1293    if @clipbbox
1294      wh = epsbbox(@clipbbox, userscale)
1295    else
1296      wh = epsbbox(bbox, userscale)
1297    end
1298    mm = wh[:nodeminmax]
1299
1300# DSC comments need fixing here...
1301    ps = "%!PS-Adobe-3.0 EPSF-2.0\n"
1302    ps += "%%Creator: osmps.rb\n"
1303    ps += "%%BoundingBox: 0 0 #{wh[:width].to_i} #{wh[:height].to_i}\n"
1304    ps += "%%EndComments\n"
1305    ps += "<< /PageSize [ #{wh[:width]} #{wh[:height]} ] /ImagingBBox null >> setpagedevice\n"
1306    ps += PSResource
1307    ps += PSSymbols
1308    ps += <<EOP
1309/mx #{mm[:minx]} def
1310/Mx #{mm[:maxx]} def
1311/my #{mm[:miny]} def
1312/My #{mm[:maxy]} def
1313/width #{wh[:width]} def
1314/height #{wh[:height]} def
1315% scale and x and y translations
1316/sc #{@scale} def
1317/x { mx sub sc mul } bd
1318/y { my sub sc mul height exch sub} bd
1319EOP
1320
1321#    ps += "% nodes\n"
1322#    ps += "newpath\n"
1323#    @nodes.keys.each do |n|
1324#      ps += "#{n.x} x #{n.y} y n\n"
1325#    end
1326#    ps += "stroke\n"
1327
1328    ps += "\n"
1329    ps += "0.1 setlinewidth\n"
1330    ps += "0 setgray\n"
1331    ps += "\n"
1332    ps += "% paths\n"
1333    ps += "1 setlinecap 1 setlinejoin\n"
1334
1335    if @clipbbox
1336      bb = @clipbbox.get
1337      ps += "np "
1338      ps += "#{bb[:minx]} #{bb[:miny]} m "
1339      ps += "#{bb[:minx]} #{bb[:maxy]} l "
1340      ps += "#{bb[:maxx]} #{bb[:maxy]} l "
1341      ps += "#{bb[:maxx]} #{bb[:miny]} l "
1342      ps += "#{bb[:minx]} #{bb[:miny]} l "
1343      ps += "closepath clip\n"
1344    end
1345
1346    # find out what layers we need to render
1347    layers = {}
1348    @tags.keys.each do |tag|
1349      tag.renderprepare(@styles)
1350      tag.renderlayers.each do |l|
1351        layers.has_key?(l) ? layers[l].push(tag) : layers[l] = [tag]
1352      end
1353    end
1354
1355    layers.keys.sort.each do |l|
1356      @tags.keys.each do |tag|
1357        if layers[l].include?(tag)
1358          content = ""
1359          if tag.styletypes.include?(:area)
1360            @areas.keys.each do |a|
1361              next if @clipbbox and a.inbbox?(@clipbbox)
1362              if a.tags == tag
1363#                puts "tag #{tag}"
1364#                puts "  area #{a} #{a.tags.to_s}"
1365#                puts "    yes"
1366                content += a.renderlayer(l)
1367              end
1368            end
1369          end
1370          if tag.styletypes.include?(:path)
1371            @paths.keys.each do |p|
1372              next if @clipbbox and p.inbbox?(@clipbbox)
1373#              puts "path #{p}: " + p.bbox.to_s
1374              if p.tags == tag
1375                content += p.renderlayer(l)
1376              end
1377            end
1378          end
1379          if content != ""
1380            ps += "% #{tag.to_s}\n"
1381            ps += tag.renderpre
1382            ps += content
1383            ps += tag.renderpost
1384          end
1385        end
1386      end
1387    end
1388   
1389    # this is currently a hack - should call render method of node class
1390    ps += "% nodes\n"
1391    @nodes.keys.each do |n|
1392      if n.tags.tags.include?("amenity")
1393        if n.tags.tags["amenity"] == "pub"
1394          ps += "np #{n.x} #{n.y} m true logo-pub\n"
1395        end
1396        if n.tags.tags["amenity"] == "parking"
1397          ps += "np #{n.x} #{n.y} m true logo-parking\n"
1398        end
1399      end
1400    end
1401
1402    ps += "%%EOF\n"
1403    ps
1404  end
1405
1406 
1407
1408# }}}
1409
1410  private
1411
1412  def taginc(tags)# {{{
1413    if tags == nil
1414      return
1415    end
1416    if @tags.has_key?(tags)
1417      @tags[tags] += 1
1418    else
1419      @tags[tags] = 1
1420    end
1421  end
1422 
1423  # }}}
1424  def tagdec(tags)# {{{
1425    if tags == nil
1426      return
1427    end
1428    if @tags.has_key?(tags)
1429      @tags[tags] -= 1
1430      if @tags[tags] == 0
1431        @tags.delete(tags)
1432      end
1433    end
1434  end
1435 
1436  # }}}
1437
1438end# }}}
1439
1440
1441if not FileTest.exist?(ARGV[0].to_s)
1442  puts "Syntax: #{$0} <filename.osm>"
1443  puts "PostScript is output on STDOUT"
1444  exit
1445end
1446
1447class Projection < Mercator# {{{
1448end# }}}
1449
1450g = Graph.new
1451#puts "Reading OSM data"
1452g.importosm(ARGV[0])
1453
1454# {{{ styles
1455#
1456#
1457# layer numbers
1458#
1459# 0    - 999     Land use / areas below everything else
1460# 1000 - 1999    Water features
1461# 2000 - 2999    Highway
1462# 3000 - 3999    Railway
1463# 4000 - 4999    Highway bridges
1464# 5000 - 5999    Railway bridges
1465#
1466#
1467#
1468# Land areas 0-999
1469#
1470
1471  s = Style.new()
1472  s.addtag("landuse", nil)
1473  s.settype(:area)
1474  s.adddrawps(0, "220 220 240 c area")  # fill in the area
1475  g.addstyle(s)
1476
1477
1478  s = Style.new()
1479  s.addtag("landuse", "residential")
1480  s.settype(:area)
1481  s.adddrawps(10, "220 220 220 c area")
1482  g.addstyle(s)
1483
1484  s = Style.new()
1485  s.addtag("landuse", "retail")
1486  s.settype(:area)
1487  s.adddrawps(10, "255 220 220 c area")
1488  g.addstyle(s)
1489
1490  s = Style.new()
1491  s.addtag("amenity", "university")
1492  s.settype(:area)
1493  s.adddrawps(10, "225 180 255 c area")
1494  g.addstyle(s)
1495
1496
1497  s = Style.new()
1498  s.addtag("leisure", "park")
1499  s.settype(:area)
1500  s.adddrawps(15, "155 215 70 c area")
1501  g.addstyle(s)
1502
1503  s = Style.new()
1504  s.addtag("amenity", "parking")
1505  s.settype(:area)
1506  s.adddrawps(20, "220 220 100 c area")
1507  g.addstyle(s)
1508
1509  s = Style.new()
1510  s.addtag("landuse", "green_space")
1511  s.settype(:area)
1512  s.adddrawps(20, "220 255 220 c area")
1513  g.addstyle(s)
1514
1515  s = Style.new()
1516  s.addtag("leisure", "pitch")
1517  s.settype(:area)
1518  s.adddrawps(20, "30 160 30 c area")
1519  g.addstyle(s)
1520
1521  s = Style.new()
1522  s.addtag("landuse", "wood")
1523  s.addtag("natural", "wood")
1524  s.settype(:area)
1525  s.adddrawps(20, "10 70 10 c area")
1526  g.addstyle(s)
1527
1528  s = Style.new()
1529  s.addtag("sport", ["bowls", "tennis"])
1530  s.settype(:area)
1531  s.adddrawps(20, "40 150 40 c area")
1532  g.addstyle(s)
1533
1534
1535# Water 1000-1999
1536
1537  s = Style.new()
1538  s.addtag("waterway", "river")
1539  s.settype(:path)
1540  s.adddrawps(1100, "0.8 lw 120 120 220 c line")
1541  g.addstyle(s)
1542
1543  s = Style.new()
1544  s.addtag("waterway", "canal")
1545  s.settype(:path)
1546  s.adddrawps(1200, "0.6 lw 70 70 220 c line")
1547  g.addstyle(s)
1548
1549  s = Style.new()
1550  s.addtag("waterway", "stream")
1551  s.settype(:path)
1552  s.adddrawps(1300, "0.4 lw 120 120 220 c line")
1553  g.addstyle(s)
1554
1555  s = Style.new()
1556  s.addtag("waterway", "drain")
1557  s.settype(:path)
1558  s.adddrawps(1350, "0.2 lw 120 120 220 c line")
1559  g.addstyle(s)
1560
1561  s = Style.new()
1562  s.addtag("natural", "water")
1563  s.settype(:area)
1564  s.adddrawps(1400, "120 120 220 c area")
1565  s.adddrawps(1401, "0.1 lw 80 80 220 c cline")
1566  g.addstyle(s)
1567
1568# Highway 2000-2999
1569
1570# update a style for a road - called with:
1571#   - style object to set
1572#   - layer for casing
1573#   - layer for core
1574#   - width (of casing)
1575#   - bridge (true or false)
1576#   - casing colour (ps snippet "r g b")
1577#   - core colour (ps snippet "r g b")
1578def setroad(sty, l1, l2, width, bridge, casecol, corecol, dash = nil)
1579  brcasew = width * 1.6
1580  brcorew = width * 1.4
1581  corew = width * 0.7
1582  sty.settype(:path)
1583  dashps = ""
1584  if dash != nil
1585    if dash.length % 2 == 0
1586      dashps = "[" + dash.join(" ") + "] 0 setdash "
1587    end
1588  end
1589  if bridge
1590    sty.addtag("bridge", "yes")
1591    sty.adddrawps(4000, "0 setlinecap #{brcasew} lw 0 0 0 c line")
1592    sty.adddrawps(4001, dashps + "0 setlinecap #{brcorew} lw 255 255 255 c line")
1593    if l1 != nil
1594      sty.adddrawps(l1 + 2000, "0 setlinecap #{width} lw #{casecol} c line") # casing over bridge
1595    end
1596    sty.adddrawps(l2 + 2100, dashps + "0 setlinecap #{corew} lw #{corecol} c line") # core
1597  else 
1598    if l1 != nil
1599      sty.adddrawps(l1, "#{width} lw #{casecol} c line")  # casing
1600    end
1601    sty.adddrawps(l2, dashps + "#{corew} lw #{corecol} c line")  # core
1602#    sty.adddrawps(2999, "pathcopy")  # name
1603    sty.adddrawtagstring(2999, "name")
1604    sty.adddrawps(2999, "roadname")
1605  end
1606end
1607
1608# loop to draw all highway-type ways for bridge / no bridge
1609for bridge in [false, true]
1610  # layer number, decremented as we go along
1611  l = 2500
1612
1613  s = Style.new()
1614  s.addtag("highway", "motorway")
1615  setroad(s, 2050, l-=20, 1, bridge, "0 0 0", "20 60 200")
1616  g.addstyle(s)
1617
1618  s = Style.new()
1619  s.addtag("highway", "trunk")
1620  setroad(s, 2050, l-=20, 1, bridge, "0 0 0", "50 150 50")
1621  g.addstyle(s)
1622
1623  s = Style.new()
1624  s.addtag("highway", "primary")
1625  setroad(s, 2050, l-=20, 1, bridge, "0 0 0", "255 50 50")
1626  g.addstyle(s)
1627
1628  s = Style.new()
1629  s.addtag("highway", "secondary")
1630  setroad(s, 2050, l-=20, 0.9, bridge, "0 0 0", "250 75 10")
1631  g.addstyle(s)
1632
1633  s = Style.new()
1634  s.addtag("highway", "tertiary")
1635  setroad(s, 2050, l-=20, 0.8, bridge, "0 0 0", "220 220 0")
1636  g.addstyle(s)
1637
1638  s = Style.new()
1639  s.addtag("highway", ["unclassified", "residential"])
1640  setroad(s, 2050, l-=20, 0.8, bridge, "0 0 0", "240 240 240")
1641  g.addstyle(s)
1642
1643  s = Style.new()
1644  s.addtag("highway", "pedestrian")
1645  setroad(s, 2050, l-=20, 0.8, bridge, "40 40 40", "200 200 200")
1646  g.addstyle(s)
1647
1648  s = Style.new()
1649  s.addtag("highway", "motorway_link")
1650  setroad(s, 2050, l-=20, 0.7, bridge, "0 0 0", "20 60 200")
1651  g.addstyle(s)
1652
1653  s = Style.new()
1654  s.addtag("highway", "trunk_link")
1655  setroad(s, 2050, l-=20, 0.7, bridge, "0 0 0", "50 150 50")
1656  g.addstyle(s)
1657
1658  s = Style.new()
1659  s.addtag("highway", "primary_link")
1660  setroad(s, 2050, l-=20, 0.7, bridge, "0 0 0", "255 50 50")
1661  g.addstyle(s)
1662
1663  s = Style.new()
1664  s.addtag("highway", "secondary_link")
1665  setroad(s, 2050, l-=20, 0.5, bridge, "0 0 0", "250 75 10")
1666  g.addstyle(s)
1667
1668  s = Style.new()
1669  s.addtag("highway", "service")
1670  setroad(s, 2050, l-=20, 0.5, bridge, "0 0 0", "250 250 250")
1671  g.addstyle(s)
1672
1673  s = Style.new()
1674  s.addtag("highway", "track")
1675  setroad(s, 2030, l-=20, 0.5, bridge, "80 30 0", "250 250 250")
1676  g.addstyle(s)
1677
1678  s = Style.new()
1679  s.addtag("highway", "cycleway")
1680  setroad(s, nil, l-=20, 0.3, bridge, nil, "0 80 0")
1681  g.addstyle(s)
1682
1683  s = Style.new()
1684  s.addtag("highway", "bridleway")
1685  setroad(s, nil, l-=20, 0.3, bridge, nil, "80 30 0", [0.5, 0.3])
1686  g.addstyle(s)
1687
1688  s = Style.new()
1689  s.addtag("highway", ["footway", "steps"])
1690  setroad(s, nil, l-=20, 0.2, bridge, nil, "80 30 0")
1691  g.addstyle(s)
1692end
1693
1694# Rail 3000 - 3999
1695
1696  s = Style.new()
1697  s.addtag("railway", "rail")
1698  s.settype(:path)
1699  s.adddrawps(3500, "1 lw 0 0 0 c line")  # core
1700  g.addstyle(s)
1701
1702  s = Style.new()
1703  s.addtag("railway", "preserved")
1704  s.settype(:path)
1705  s.adddrawps(3300, "0.6 lw 25 25 25 c line")  # core
1706  g.addstyle(s)
1707
1708# }}}
1709
1710puts g.eps
1711
1712# simple example of how to chop map up into 4x4 and output to
1713# different files for a multi-page booklet:
1714#
1715# prefix = "output-"
1716#
1717# wblocks = 4
1718# hblocks = 4
1719#
1720# wstep = g.lonlatbbox.width / wblocks
1721# hstep = g.lonlatbbox.height / hblocks
1722#
1723# for lat in 1..hblocks
1724#   for lon in 1..wblocks
1725#     File.open("#{prefix}-#{lon}-#{lat}.eps", "w") do |f|
1726#       g.setclip(g.lonlatbbox.minx + (wstep * (lon-1)),
1727#                 g.lonlatbbox.miny + (hstep * (lat-1)),
1728#                 g.lonlatbbox.minx + (wstep * lon),
1729#                 g.lonlatbbox.miny + (hstep * lat))
1730#       f.puts g.eps
1731#     end
1732#   end
1733# end
1734
Note: See TracBrowser for help on using the repository browser.