2 * Hic Est Leo -- Global Map Operations
4 * (c) 2014--2015 Martin Mares <mj@ucw.cz>
10 #include <ucw/mempool.h>
11 #include <ucw/simple-lists.h>
24 double map_min_x, map_min_y;
25 double map_max_x, map_max_y;
26 double page_width, page_height;
27 uns map_clip, map_rotate, map_draw_border;
30 char *map_style_sheet;
34 static struct cf_section map_style_cf = {
35 #define P(x) PTR_TO(struct data_source_style, x)
36 CF_TYPE(struct data_source_style),
38 CF_STRING("Name", P(name)),
44 static const char * const map_formats[] = {
51 static struct cf_section map_source_cf = {
52 #define P(x) PTR_TO(struct data_source, x)
53 CF_TYPE(struct data_source),
55 CF_STRING("File", P(file)),
56 CF_LOOKUP("Format", P(format), map_formats),
57 CF_LIST("StyleSheet", P(styles), &map_style_cf),
58 CF_INT("InlineStyles", P(inline_styles)),
64 static struct cf_section map_cf = {
66 CF_DOUBLE("MinX", &map_min_x),
67 CF_DOUBLE("MinY", &map_min_y),
68 CF_DOUBLE("MaxX", &map_max_x),
69 CF_DOUBLE("MaxY", &map_max_y),
70 CF_DOUBLE("PageWidth", &page_width),
71 CF_DOUBLE("PageHeight", &page_height),
72 CF_UNS("Clip", &map_clip),
73 CF_UNS("Rotate", &map_rotate),
74 CF_UNS("DrawBorder", &map_draw_border),
75 CF_LIST("Source", &map_sources, &map_source_cf),
76 CF_STRING("Projection", &map_projection),
77 CF_STRING("SVGOutput", &map_svg_output),
82 static void CONSTRUCTOR map_preinit(void)
84 cf_declare_section("Map", &map_cf, 0);
89 double page_offset_x, page_offset_y;
90 double page_map_width, page_map_height;
92 void map_set_scale(void)
94 double x_range = map_max_x - map_min_x;
95 double y_range = map_max_y - map_min_y;
96 double x_scale = page_width / x_range;
97 double y_scale = page_height / y_range;
98 map_scale = MIN(x_scale, y_scale);
99 page_map_width = x_range * map_scale;
100 page_map_height = y_range * map_scale;
101 page_offset_x = (page_width - page_map_width) / 2;
102 page_offset_y = (page_height - page_map_height) / 2;
104 msg(L_INFO, "Setting scale %.3g (orig window [%.6g,%.6g], page window [%.6g,%.6g]+[%.6g,%.6g] on [%.6g,%.6g])",
107 page_map_width, page_map_height,
108 page_offset_x, page_offset_y,
109 page_width, page_height);
111 double pmin_x = INFINITY, pmax_x = -INFINITY;
112 double pmin_y = INFINITY, pmax_y = -INFINITY;
113 double rmin_x = INFINITY, rmax_x = -INFINITY;
114 double rmin_y = INFINITY, rmax_y = -INFINITY;
115 CLIST_FOR_EACH(struct data_source *, ds, map_sources)
117 if (ds->format == DATA_SOURCE_FIXED)
119 CLIST_FOR_EACH(struct osm_node *, n, ds->osm->obj_list[OSM_TYPE_NODE])
121 pmin_x = MIN(pmin_x, n->x);
122 pmax_x = MAX(pmax_x, n->x);
123 pmin_y = MIN(pmin_y, n->y);
124 pmax_y = MAX(pmax_y, n->y);
125 n->x = (n->x - map_min_x) * map_scale + page_offset_x;
126 n->y = page_height - page_offset_y - (n->y - map_min_y) * map_scale;
127 rmin_x = MIN(rmin_x, n->x);
128 rmax_x = MAX(rmax_x, n->x);
129 rmin_y = MIN(rmin_y, n->y);
130 rmax_y = MAX(rmax_y, n->y);
133 msg(L_INFO, "Bounds before scaling: [%.10g,%.10g] x [%.10g,%.10g]", pmin_x, pmax_x, pmin_y, pmax_y);
134 msg(L_INFO, "Bounds after scaling: [%.10g,%.10g] x [%.10g,%.10g]", rmin_x, rmax_x, rmin_y, rmax_y);
136 if (debug_dump_after_scaling)
138 puts("=== Map after scaling ===");
139 CLIST_FOR_EACH(struct data_source *, ds, map_sources)
147 bool map_object_visible_p(struct osm_object *o)
155 struct osm_node *n = (struct osm_node *) o;
156 return (n->x >= page_offset_x - margin && n->x <= page_offset_x + page_map_width + margin &&
157 n->y >= page_offset_y - margin && n->y <= page_offset_y + page_map_height + margin);
161 struct osm_way *w = (struct osm_way *) o;
163 OSM_FOR_EACH_BEGIN(struct osm_object *, n, w->nodes)
165 ok |= map_object_visible_p(n);
170 case OSM_TYPE_RELATION:
172 struct osm_relation *r = (struct osm_relation *) o;
174 OSM_FOR_EACH_BEGIN(struct osm_object *, n, r->members)
176 ok |= map_object_visible_p(n);
181 case OSM_TYPE_MULTIPOLYGON:
182 return map_object_visible_p(&((struct osm_multipolygon *) o)->rel->o);
188 void map_load_styles(void)
191 clist_init(&style_cache);
193 CLIST_FOR_EACH(struct data_source *, ds, map_sources)
195 CLIST_FOR_EACH(struct data_source_style *, ss, ds->styles)
197 CLIST_FOR_EACH(struct simp_node *, n, style_cache)
199 struct data_source_style *x = n->p;
200 if (!strcmp(x->name, ss->name))
208 msg(L_DEBUG, "Loading style sheet %s", ss->name);
209 ss->css = css_load(ss->name);
213 printf("=== Stylesheet %s ===", ss->name);
217 simp_append(cf_get_pool(), &style_cache)->p = ss;
223 static void map_load_source(struct data_source *ds)
225 ds->osm = osm_init();
232 case DATA_SOURCE_OSMXML:
233 msg(L_INFO, "Parsing %s as OSM XML", ds->file);
235 die("OSM XML data sources must have a file name");
236 osm_xml_parse(ds->file);
240 case DATA_SOURCE_FIXED:
241 msg(L_INFO, "Adding fixed objects");
246 case DATA_SOURCE_SHAPE:
247 msg(L_INFO, "Parsing %s as shape file", ds->file);
249 die("Shape data sources must have a file name");
254 die("Invalid data source format");
258 if (debug_dump_source)
260 puts("=== Source data ===");
264 osm_make_multipolygons();
268 msg(L_INFO, "Projecting");
269 osm_project(map_projection);
270 if (debug_dump_after_proj)
272 puts("=== Map after projection ===");
278 void map_load_sources(void)
280 CLIST_FOR_EACH(struct data_source *, ds, map_sources)
284 static void map_apply_inline_styles(struct osm_object *o, struct style_results *r)
288 CLIST_FOR_EACH(struct osm_tag *, t, o->tags)
290 const char *key = osm_key_decode(t->key);
291 if (!strncmp(key, "style:", 6))
294 layer_t layer = STYLE_LAYER_DEFAULT;
295 char *sep = strstr(key, "::");
300 // XXX: Only layers defined in the main stylesheet can be modified
301 layer = style_layer_encode_if_exists(sep+2);
305 int keylen = sep - key;
306 char *t = mp_alloc(r->pool, keylen+1);
307 memcpy(t, key, keylen);
313 name = mp_printf(r->pool, "Inline style in object #%ju", (uintmax_t) o->id);
314 struct style_prop *p= css_parse_prop(r->pool, name, key, osm_val_decode(t->val));
315 style_set_by_layer(r, layer, p);
321 void map_apply_styles(struct svg *svg)
323 struct style_results r;
326 CLIST_FOR_EACH(struct data_source *, ds, map_sources)
328 msg(L_INFO, "Applying stylesheet on %s", ds->file);
329 for (uns i = OSM_TYPE_NODE; i <= OSM_TYPE_MULTIPOLYGON; i++)
330 CLIST_FOR_EACH(struct osm_object *, o, ds->osm->obj_list[i])
332 if (debug_dump_styling)
334 puts("===============================");
337 if (!map_object_visible_p(o))
339 if (debug_dump_styling)
340 printf("--> invisible\n");
344 CLIST_FOR_EACH(struct data_source_style *, ss, ds->styles)
345 css_apply(ss->css, &r);
346 if (ds->inline_styles)
347 map_apply_inline_styles(o, &r);
348 if (debug_dump_styling)
350 sym_from_style(o, &r, svg);