В Ubuntu 22.04 сломали проекции в Mapnik, приходится использовать альтернативный...
[pyrungps.git] / pyrungps / generate_image.py
1 #!/usr/bin/env python
2
3 import mapnik
4
5 import sys, os
6
7 from lxml import html,etree
8 from optparse import OptionParser
9
10 from pprint import pprint
11
12 from pyrungps.pygpx import GPX
13
14 from pyproj import Transformer
15
16 # Set up projections
17 # spherical mercator (most common target map projection of osm data imported with osm2pgsql)
18 #merc = mapnik.Projection('+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs +over')
19
20 # long/lat in degrees, aka ESPG:4326 and "WGS 84" 
21 #longlat = mapnik.Projection('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
22 # can also be constructed as:
23 #longlat = mapnik.Projection('+init=epsg:4326')
24
25 # ensure minimum mapnik version
26 if not hasattr(mapnik,'mapnik_version') and not mapnik.mapnik_version() >= 600:
27     raise SystemExit('This script requires Mapnik >=0.6.0)')
28
29
30 def render_map(mapfile,map_uri,gpx_file,imgx,imgy):
31
32     with open(gpx_file,'r') as f:
33       data = f.read()
34
35     xml = etree.fromstring(data)
36     gpx = GPX()
37     gpx.ReadTree(xml)
38
39     bbox = gpx.bound_box()
40     pprint(bbox)
41     cx=(bbox[0][1]+bbox[1][1])/2
42     cy=(bbox[0][0]+bbox[1][0])/2
43     print(cx,cy)
44     w=(bbox[1][1]-bbox[0][1])*1.2
45     h=(bbox[1][0]-bbox[0][0])*1.2
46     print(w,h)
47     bounds = (cx-w/2,cy-h/2,cx+w/2,cy+h/2)
48     print(bounds)
49
50     m = mapnik.Map(imgx,imgy)
51     mapnik.load_map(m,mapfile)
52
53     m.background = mapnik.Color('rgb(255,255,255)')
54     
55     # ensure the target map projection is mercator
56     #m.srs = merc.params()
57
58     bbox = mapnik.Box2d(*bounds)
59
60     pprint(bbox)
61    
62     minlat = bbox.miny
63     maxlat = bbox.maxy
64     minlon = bbox.minx
65     maxlon = bbox.maxx
66
67     print(minlat,maxlat,minlon,maxlon)
68     
69     transformer = Transformer.from_crs("EPSG:4326", "EPSG:3857", always_xy=True)
70     minP=transformer.transform(minlon,minlat)
71     maxP=transformer.transform(maxlon,maxlat)
72     
73     merc_bbox = mapnik.Box2d(minP[0],minP[1],maxP[0],maxP[1])
74     m.zoom_to_box(merc_bbox)
75
76     style = mapnik.Style()
77     rule = mapnik.Rule()
78
79     line_symbolizer = mapnik.LineSymbolizer()
80
81     line_symbolizer.stroke = mapnik.Color('rgb(0,0,127)')
82     line_symbolizer.stroke_width = 4.0
83     line_symbolizer.stroke_opacity = 0.5
84     
85     rule.symbols.append(line_symbolizer)
86
87     style.rules.append(rule)
88     m.append_style('GPS_tracking_points', style)
89
90     layer = mapnik.Layer('GPS_tracking_points')
91     layer.datasource = mapnik.Ogr(file=gpx_file, layer='tracks')
92     layer.styles.append('GPS_tracking_points')
93     m.layers.append(layer)
94
95     im = mapnik.Image(imgx,imgy)
96     mapnik.render(m, im)
97     im.save(map_uri,'png')
98     sys.stdout.write('output image to %s!\n' % map_uri)
99
100
101 def render_all(db,mapfile,imgx,imgy):
102
103     import sqlite3
104     from os.path import dirname    
105
106     conn = sqlite3.connect(db)
107     conn.text_factory = str
108     cur = conn.cursor()
109     updcur = conn.cursor()
110
111     cur.execute ("select id,filename from tracks where preview_name is null")
112     
113     list=cur.fetchall()
114     
115     for rec in list:        
116     
117       id = rec[0]
118       filename = rec[1]
119       preview_name = dirname(filename) + '/' + str(id) + '.png'
120
121       print(id,filename,preview_name)
122
123       try:      
124         render_map(mapfile,preview_name.encode('utf8'),filename,imgx,imgy)
125         updcur.execute("update tracks set preview_name=? where id=?", (preview_name,id))
126         conn.commit()
127       except:
128         raise
129
130
131 def main():
132
133     parser = OptionParser()
134     parser.add_option("-m", "--map", dest="mapfile",
135       help="use map file", metavar="MAP")
136     parser.add_option("-o", "--output", dest="outfile",
137       help="output image to file", metavar="OUT")
138     parser.add_option("-g", "--gpx", dest="gpxfile",
139       help="track to render", metavar="GPX")
140     parser.add_option("-x", "--x-size", dest="x",
141       help="image width", metavar="X")
142     parser.add_option("-y", "--y-size", dest="y",
143       help="image height", metavar="Y")
144     parser.add_option("-d", "--db", dest="db",
145       help="render all not process files in database", metavar="DB")
146     (options, args) = parser.parse_args()
147
148     if options.mapfile:  
149       mapfile = options.mapfile
150     else:
151       mapfile = "/etc/mapnik-osm-carto-data/veloroad-imposm.xml"
152
153     if options.outfile:  
154       map_uri = options.outfile
155     else:
156       map_uri = "image.png"
157
158     if options.x:  
159       imgx = int(options.x)
160     else:
161       imgx= 640
162     if options.y:  
163       imgy = int(options.y)
164     else:
165       imgy= 640
166
167     if options.db:
168       render_all(options.db,mapfile,imgx,imgy) 
169     else:
170       if options.gpxfile:  
171         gpx_file = options.gpxfile
172         render_map(mapfile,map_uri,gpx_file,imgx,imgy)
173       else:
174         print("No input file")
175         raise IOError("No input file")
176
177 if __name__ == "__main__":
178
179     try:
180         main()                    
181     except:
182         exit(1)