]> mj.ucw.cz Git - leo.git/blob - map.c
2aab9e2c66cdbe2687187277e37bc99ccea5de97
[leo.git] / map.c
1 /*
2  *      Hic Est Leo -- Global Map Operations
3  *
4  *      (c) 2014 Martin Mares <mj@ucw.cz>
5  */
6
7 #include <ucw/lib.h>
8 #include <ucw/conf.h>
9 #include <ucw/gary.h>
10 #include <ucw/mempool.h>
11 #include <ucw/simple-lists.h>
12
13 #include <stdio.h>
14 #include <math.h>
15
16 #include "leo.h"
17 #include "osm.h"
18 #include "map.h"
19 #include "css.h"
20 #include "sym.h"
21
22 double map_min_x, map_min_y;
23 double map_max_x, map_max_y;
24 double page_width, page_height;
25 uns map_clip, map_rotate, map_draw_border;
26 char *map_xml_input;
27 char *map_projection;
28 char *map_style_sheet;
29 char *map_svg_output;
30 clist map_sources;
31
32 static struct cf_section map_style_cf = {
33 #define P(x) PTR_TO(struct data_source_style, x)
34   CF_TYPE(struct data_source_style),
35   CF_ITEMS {
36     CF_STRING("Name", P(name)),
37     CF_END
38   }
39 #undef P
40 };
41
42 static const char * const map_formats[] = {
43   "invalid",
44   "osmxml",
45 };
46
47 static struct cf_section map_source_cf = {
48 #define P(x) PTR_TO(struct data_source, x)
49   CF_TYPE(struct data_source),
50   CF_ITEMS {
51     CF_STRING("File", P(file)),
52     CF_LOOKUP("Format", P(format), map_formats),
53     CF_LIST("StyleSheet", P(styles), &map_style_cf),
54     CF_END
55   }
56 #undef P
57 };
58
59 static struct cf_section map_cf = {
60   CF_ITEMS {
61     CF_DOUBLE("MinX", &map_min_x),
62     CF_DOUBLE("MinY", &map_min_y),
63     CF_DOUBLE("MaxX", &map_max_x),
64     CF_DOUBLE("MaxY", &map_max_y),
65     CF_DOUBLE("PageWidth", &page_width),
66     CF_DOUBLE("PageHeight", &page_height),
67     CF_UNS("Clip", &map_clip),
68     CF_UNS("Rotate", &map_rotate),
69     CF_UNS("DrawBorder", &map_draw_border),
70     CF_LIST("Source", &map_sources, &map_source_cf),
71     CF_STRING("Projection", &map_projection),
72     CF_STRING("SVGOutput", &map_svg_output),
73     CF_END
74   }
75 };
76
77 static void CONSTRUCTOR map_preinit(void)
78 {
79   cf_declare_section("Map", &map_cf, 0);
80 }
81
82 // Calculated
83 double map_scale;
84 double page_offset_x, page_offset_y;
85 double page_map_width, page_map_height;
86
87 void map_set_scale(void)
88 {
89   double x_range = map_max_x - map_min_x;
90   double y_range = map_max_y - map_min_y;
91   double x_scale = page_width / x_range;
92   double y_scale = page_height / y_range;
93   map_scale = MIN(x_scale, y_scale);
94   page_map_width = x_range * map_scale;
95   page_map_height = y_range * map_scale;
96   page_offset_x = (page_width - page_map_width) / 2;
97   page_offset_y = (page_height - page_map_height) / 2;
98
99   msg(L_INFO, "Setting scale %.3g (orig window [%.6g,%.6g], page window [%.6g,%.6g]+[%.6g,%.6g] on [%.6g,%.6g])",
100     map_scale,
101     x_range, y_range,
102     page_map_width, page_map_height,
103     page_offset_x, page_offset_y,
104     page_width, page_height);
105
106   double pmin_x = INFINITY, pmax_x = -INFINITY;
107   double pmin_y = INFINITY, pmax_y = -INFINITY;
108   double rmin_x = INFINITY, rmax_x = -INFINITY;
109   double rmin_y = INFINITY, rmax_y = -INFINITY;
110   CLIST_FOR_EACH(struct data_source *, ds, map_sources)
111     {
112       CLIST_FOR_EACH(struct osm_node *, n, ds->osm->obj_list[OSM_TYPE_NODE])
113         {
114           pmin_x = MIN(pmin_x, n->x);
115           pmax_x = MAX(pmax_x, n->x);
116           pmin_y = MIN(pmin_y, n->y);
117           pmax_y = MAX(pmax_y, n->y);
118           n->x = (n->x - map_min_x) * map_scale + page_offset_x;
119           n->y = page_height - page_offset_y - (n->y - map_min_y) * map_scale;
120           rmin_x = MIN(rmin_x, n->x);
121           rmax_x = MAX(rmax_x, n->x);
122           rmin_y = MIN(rmin_y, n->y);
123           rmax_y = MAX(rmax_y, n->y);
124         }
125     }
126   msg(L_INFO, "Bounds before scaling: [%.10g,%.10g] x [%.10g,%.10g]", pmin_x, pmax_x, pmin_y, pmax_y);
127   msg(L_INFO, "Bounds after scaling: [%.10g,%.10g] x [%.10g,%.10g]", rmin_x, rmax_x, rmin_y, rmax_y);
128
129   if (debug_dump_after_scaling)
130     {
131       puts("=== Map after scaling ===");
132       CLIST_FOR_EACH(struct data_source *, ds, map_sources)
133         {
134           osm_this = ds->osm;
135           osm_dump();
136         }
137     }
138 }
139
140 bool map_object_visible_p(struct osm_object *o)
141 {
142   double margin = 10;
143
144   switch (o->type)
145     {
146     case OSM_TYPE_NODE:
147       {
148         struct osm_node *n = (struct osm_node *) o;
149         return (n->x >= page_offset_x - margin && n->x <= page_offset_x + page_map_width + margin &&
150                 n->y >= page_offset_y - margin && n->y <= page_offset_y + page_map_height + margin);
151       }
152     case OSM_TYPE_WAY:
153       {
154         struct osm_way *w = (struct osm_way *) o;
155         bool ok = 0;
156         OSM_FOR_EACH_BEGIN(struct osm_object *, n, w->nodes)
157           {
158             ok |= map_object_visible_p(n);
159           }
160         OSM_FOR_EACH_END;
161         return ok;
162       }
163     case OSM_TYPE_RELATION:
164       {
165         struct osm_relation *r = (struct osm_relation *) o;
166         bool ok = 0;
167         OSM_FOR_EACH_BEGIN(struct osm_object *, n, r->members)
168           {
169             ok |= map_object_visible_p(n);
170           }
171         OSM_FOR_EACH_END;
172         return ok;
173       }
174     case OSM_TYPE_MULTIPOLYGON:
175       return map_object_visible_p(&((struct osm_multipolygon *) o)->rel->o);
176     default:
177       ASSERT(0);
178     }
179 }
180
181 void map_load_styles(void)
182 {
183   clist style_cache;
184   clist_init(&style_cache);
185
186   CLIST_FOR_EACH(struct data_source *, ds, map_sources)
187     {
188       CLIST_FOR_EACH(struct data_source_style *, ss, ds->styles)
189         {
190           CLIST_FOR_EACH(struct simp_node *, n, style_cache)
191             {
192               struct data_source_style *x = n->p;
193               if (!strcmp(x->name, ss->name))
194                 {
195                   ss->css = x->css;
196                   break;
197                 }
198             }
199           if (!ss->css)
200             {
201               msg(L_DEBUG, "Loading style sheet %s", ss->name);
202               ss->css = css_load(ss->name);
203
204               if (debug_dump_css)
205                 {
206                   printf("=== Stylesheet %s ===", ss->name);
207                   css_dump(ss->css);
208                 }
209
210               simp_append(cf_get_pool(), &style_cache)->p = ss;
211             }
212         }
213     }
214 }
215
216 static void map_load_source(struct data_source *ds)
217 {
218   ds->osm = osm_init();
219
220   switch (ds->format)
221     {
222     case DATA_SOURCE_OSMXML:
223       msg(L_INFO, "Parsing %s as OSM XML", ds->file);
224       osm_xml_parse(ds->file);
225       if (debug_dump_source)
226         {
227           puts("=== Source data ===");
228           osm_dump();
229         }
230       osm_make_multipolygons();
231       break;
232     default:
233       die("Invalid data source format");
234     }
235
236   msg(L_INFO, "Projecting");
237   osm_project(map_projection);
238   if (debug_dump_after_proj)
239     {
240       puts("=== Map after projection ===");
241       osm_dump();
242     }
243 }
244
245 void map_load_sources(void)
246 {
247   CLIST_FOR_EACH(struct data_source *, ds, map_sources)
248     map_load_source(ds);
249 }
250
251 void map_apply_styles(struct svg *svg)
252 {
253   struct style_results r;
254   style_init(&r);
255
256   CLIST_FOR_EACH(struct data_source *, ds, map_sources)
257     {
258       msg(L_INFO, "Applying stylesheet on %s", ds->file);
259       for (uns i = OSM_TYPE_NODE; i <= OSM_TYPE_MULTIPOLYGON; i++)
260         CLIST_FOR_EACH(struct osm_object *, o, ds->osm->obj_list[i])
261           {
262             if (debug_dump_styling)
263               {
264                 puts("===============================");
265                 osm_obj_dump(o);
266               }
267             if (!map_object_visible_p(o))
268               {
269                 if (debug_dump_styling)
270                   printf("--> invisible\n");
271                 continue;
272               }
273             style_begin(&r, o);
274             CLIST_FOR_EACH(struct data_source_style *, ss, ds->styles)
275               css_apply(ss->css, &r);
276             if (debug_dump_styling)
277               style_dump(&r);
278             sym_from_style(o, &r, svg);
279             style_end(&r);
280           }
281     }
282
283   // FIXME: Ought to destroy the style_results
284 }