From b5ad4205a047a4be68e74c82f5637b13bd3f6896 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Sun, 15 Jun 2014 23:30:47 +0200 Subject: [PATCH 1/1] Introduced multiple data sources --- leo.c | 57 +------------------ leo.h | 4 -- map.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- map.cf | 17 ++++-- map.h | 34 ++++++++++- osm.c | 60 +++++++++++--------- osm.h | 16 +++++- xml.c | 2 - 8 files changed, 254 insertions(+), 110 deletions(-) diff --git a/leo.c b/leo.c index dea6cde..5d02f68 100644 --- a/leo.c +++ b/leo.c @@ -118,37 +118,9 @@ int main(int argc UNUSED, char **argv) osm_init(); styles_init(); - - msg(L_INFO, "Parsing OSM"); - osm_xml_parse(map_xml_input); - if (debug_dump_source) - { - puts("=== Source data ==="); - osm_dump(); - } - osm_make_multipolygons(); - - msg(L_INFO, "Projecting"); - osm_project(map_projection); - if (debug_dump_after_proj) - { - puts("=== Map after projection ==="); - osm_dump(); - } - + map_load_styles(); + map_load_sources(); map_set_scale(); - if (debug_dump_after_scaling) - { - puts("=== Map after scaling ==="); - osm_dump(); - } - - struct css_sheet *ss = css_load(map_style_sheet); - if (debug_dump_css) - { - puts("=== Stylesheet ==="); - css_dump(ss); - } struct svg *svg = svg_open(map_svg_output); if (!map_rotate) @@ -162,32 +134,9 @@ int main(int argc UNUSED, char **argv) svg_set_attr_dimen(svg, "height", page_width); } - struct style_results r; - style_init(&r); sym_init(); - msg(L_INFO, "Applying stylesheet"); - for (uns i = OSM_TYPE_NODE; i <= OSM_TYPE_MULTIPOLYGON; i++) - CLIST_FOR_EACH(struct osm_object *, o, osm_obj_list[i]) - { - if (debug_dump_styling) - { - puts("==============================="); - osm_obj_dump(o); - } - if (!map_object_visible_p(o)) - { - if (debug_dump_styling) - printf("--> invisible\n"); - continue; - } - style_begin(&r, o); - css_apply(ss, &r); - if (debug_dump_styling) - style_dump(&r); - sym_from_style(o, &r, svg); - style_end(&r); - } + map_apply_styles(svg); if (map_clip) { diff --git a/leo.h b/leo.h index d5d8a56..f753065 100644 --- a/leo.h +++ b/leo.h @@ -16,7 +16,3 @@ typedef u32 color_t; // 0x00RRGGBB extern uns debug_dump_source, debug_dump_after_proj, debug_dump_after_scaling; extern uns debug_dump_multipolygons, debug_dump_css, debug_dump_styling, debug_dump_symbols; - -/* xml.c */ - -void osm_xml_parse(const char *name); diff --git a/map.c b/map.c index 455d7aa..2aab9e2 100644 --- a/map.c +++ b/map.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -15,6 +16,8 @@ #include "leo.h" #include "osm.h" #include "map.h" +#include "css.h" +#include "sym.h" double map_min_x, map_min_y; double map_max_x, map_max_y; @@ -24,6 +27,34 @@ char *map_xml_input; char *map_projection; char *map_style_sheet; char *map_svg_output; +clist map_sources; + +static struct cf_section map_style_cf = { +#define P(x) PTR_TO(struct data_source_style, x) + CF_TYPE(struct data_source_style), + CF_ITEMS { + CF_STRING("Name", P(name)), + CF_END + } +#undef P +}; + +static const char * const map_formats[] = { + "invalid", + "osmxml", +}; + +static struct cf_section map_source_cf = { +#define P(x) PTR_TO(struct data_source, x) + CF_TYPE(struct data_source), + CF_ITEMS { + CF_STRING("File", P(file)), + CF_LOOKUP("Format", P(format), map_formats), + CF_LIST("StyleSheet", P(styles), &map_style_cf), + CF_END + } +#undef P +}; static struct cf_section map_cf = { CF_ITEMS { @@ -36,9 +67,8 @@ static struct cf_section map_cf = { CF_UNS("Clip", &map_clip), CF_UNS("Rotate", &map_rotate), CF_UNS("DrawBorder", &map_draw_border), - CF_STRING("XMLInput", &map_xml_input), + CF_LIST("Source", &map_sources, &map_source_cf), CF_STRING("Projection", &map_projection), - CF_STRING("StyleSheet", &map_style_sheet), CF_STRING("SVGOutput", &map_svg_output), CF_END } @@ -77,21 +107,34 @@ void map_set_scale(void) double pmin_y = INFINITY, pmax_y = -INFINITY; double rmin_x = INFINITY, rmax_x = -INFINITY; double rmin_y = INFINITY, rmax_y = -INFINITY; - CLIST_FOR_EACH(struct osm_node *, n, osm_obj_list[OSM_TYPE_NODE]) + CLIST_FOR_EACH(struct data_source *, ds, map_sources) { - pmin_x = MIN(pmin_x, n->x); - pmax_x = MAX(pmax_x, n->x); - pmin_y = MIN(pmin_y, n->y); - pmax_y = MAX(pmax_y, n->y); - n->x = (n->x - map_min_x) * map_scale + page_offset_x; - n->y = page_height - page_offset_y - (n->y - map_min_y) * map_scale; - rmin_x = MIN(rmin_x, n->x); - rmax_x = MAX(rmax_x, n->x); - rmin_y = MIN(rmin_y, n->y); - rmax_y = MAX(rmax_y, n->y); + CLIST_FOR_EACH(struct osm_node *, n, ds->osm->obj_list[OSM_TYPE_NODE]) + { + pmin_x = MIN(pmin_x, n->x); + pmax_x = MAX(pmax_x, n->x); + pmin_y = MIN(pmin_y, n->y); + pmax_y = MAX(pmax_y, n->y); + n->x = (n->x - map_min_x) * map_scale + page_offset_x; + n->y = page_height - page_offset_y - (n->y - map_min_y) * map_scale; + rmin_x = MIN(rmin_x, n->x); + rmax_x = MAX(rmax_x, n->x); + rmin_y = MIN(rmin_y, n->y); + rmax_y = MAX(rmax_y, n->y); + } } msg(L_INFO, "Bounds before scaling: [%.10g,%.10g] x [%.10g,%.10g]", pmin_x, pmax_x, pmin_y, pmax_y); msg(L_INFO, "Bounds after scaling: [%.10g,%.10g] x [%.10g,%.10g]", rmin_x, rmax_x, rmin_y, rmax_y); + + if (debug_dump_after_scaling) + { + puts("=== Map after scaling ==="); + CLIST_FOR_EACH(struct data_source *, ds, map_sources) + { + osm_this = ds->osm; + osm_dump(); + } + } } bool map_object_visible_p(struct osm_object *o) @@ -134,3 +177,108 @@ bool map_object_visible_p(struct osm_object *o) ASSERT(0); } } + +void map_load_styles(void) +{ + clist style_cache; + clist_init(&style_cache); + + CLIST_FOR_EACH(struct data_source *, ds, map_sources) + { + CLIST_FOR_EACH(struct data_source_style *, ss, ds->styles) + { + CLIST_FOR_EACH(struct simp_node *, n, style_cache) + { + struct data_source_style *x = n->p; + if (!strcmp(x->name, ss->name)) + { + ss->css = x->css; + break; + } + } + if (!ss->css) + { + msg(L_DEBUG, "Loading style sheet %s", ss->name); + ss->css = css_load(ss->name); + + if (debug_dump_css) + { + printf("=== Stylesheet %s ===", ss->name); + css_dump(ss->css); + } + + simp_append(cf_get_pool(), &style_cache)->p = ss; + } + } + } +} + +static void map_load_source(struct data_source *ds) +{ + ds->osm = osm_init(); + + switch (ds->format) + { + case DATA_SOURCE_OSMXML: + msg(L_INFO, "Parsing %s as OSM XML", ds->file); + osm_xml_parse(ds->file); + if (debug_dump_source) + { + puts("=== Source data ==="); + osm_dump(); + } + osm_make_multipolygons(); + break; + default: + die("Invalid data source format"); + } + + msg(L_INFO, "Projecting"); + osm_project(map_projection); + if (debug_dump_after_proj) + { + puts("=== Map after projection ==="); + osm_dump(); + } +} + +void map_load_sources(void) +{ + CLIST_FOR_EACH(struct data_source *, ds, map_sources) + map_load_source(ds); +} + +void map_apply_styles(struct svg *svg) +{ + struct style_results r; + style_init(&r); + + CLIST_FOR_EACH(struct data_source *, ds, map_sources) + { + msg(L_INFO, "Applying stylesheet on %s", ds->file); + for (uns i = OSM_TYPE_NODE; i <= OSM_TYPE_MULTIPOLYGON; i++) + CLIST_FOR_EACH(struct osm_object *, o, ds->osm->obj_list[i]) + { + if (debug_dump_styling) + { + puts("==============================="); + osm_obj_dump(o); + } + if (!map_object_visible_p(o)) + { + if (debug_dump_styling) + printf("--> invisible\n"); + continue; + } + style_begin(&r, o); + CLIST_FOR_EACH(struct data_source_style *, ss, ds->styles) + css_apply(ss->css, &r); + if (debug_dump_styling) + style_dump(&r); + sym_from_style(o, &r, svg); + style_end(&r); + } + } + + // FIXME: Ought to destroy the style_results +} diff --git a/map.cf b/map.cf index a6ae531..c55a3e7 100644 --- a/map.cf +++ b/map.cf @@ -1,6 +1,16 @@ Map { - # Source file with XML map of OSM data - XMLInput dump.osm + # Data sources + Source { + # Input file + File dump.osm + + # File format: + # osmxml OpenStreetMap XML + Format osmxml + + # MapCSS stylesheet to apply (multiple style-sheets are allowed) + StyleSheet poskole.css + } # Projection of our map Projection "+proj=utm +zone=33 +ellps=WGS84" @@ -28,9 +38,6 @@ Map { # Draw blue border around the requested rectangle DrawBorder 0 - # MapCSS stylesheet to apply - StyleSheet poskole.css - # Write SVG output here SVGOutput output.svg } diff --git a/map.h b/map.h index 127d30a..f031f7b 100644 --- a/map.h +++ b/map.h @@ -7,17 +7,43 @@ #ifndef _LEO_MAP_H #define _LEO_MAP_H +#include "svg.h" + /* Map configuration */ extern double map_min_x, map_min_y; extern double map_max_x, map_max_y; extern double page_width, page_height; extern uns map_clip, map_rotate, map_draw_border; -extern char *map_xml_input; extern char *map_projection; -extern char *map_style_sheet; extern char *map_svg_output; +// Remember to update map.c:map_formats +enum data_source_type { + DATA_SOURCE_INVALID, + DATA_SOURCE_OSMXML, +}; + +struct data_source { + cnode n; + // Configuration + char *file; + int format; + clist styles; // of data_source_style + // Runtime + struct osm *osm; +}; + +struct data_source_style { + cnode n; + // Configuration + char *name; + // Runtime + struct css_sheet *css; +}; + +extern clist map_sources; + /* Calculated by map_set_scale() */ extern double map_scale; @@ -27,4 +53,8 @@ extern double page_map_width, page_map_height; void map_set_scale(void); bool map_object_visible_p(struct osm_object *o); +void map_load_styles(void); +void map_load_sources(void); +void map_apply_styles(struct svg *svg); + #endif diff --git a/osm.c b/osm.c index 12529f6..325b592 100644 --- a/osm.c +++ b/osm.c @@ -17,7 +17,7 @@ #include "leo.h" #include "osm.h" -static struct mempool *osm_pool; +struct osm *osm_this; /*** Generic objects ***/ @@ -26,8 +26,6 @@ struct osm_id_to_obj { struct osm_object *o; }; -clist osm_obj_list[OSM_TYPE_MAX]; - #define P(x) [OSM_TYPE_##x] = #x, const char * const osm_obj_type_names[OSM_TYPE_MAX] = { [OSM_TYPE_INVALID] = "Invalid", @@ -44,13 +42,12 @@ const char * const osm_obj_type_names[OSM_TYPE_MAX] = { #define HASH_ATOMIC_TYPE osm_id_t #define HASH_WANT_FIND #define HASH_WANT_LOOKUP -#define HASH_USE_POOL osm_pool +#define HASH_TABLE_VARS struct mempool *pool; +#define HASH_USE_POOL table->pool #define HASH_ZERO_FILL #define HASH_TABLE_DYNAMIC #include -static struct osm_id_hash_table osm_id_hash[OSM_TYPE_MAX]; - osm_id_t osm_parse_id(const char *str) { uintmax_t id; @@ -64,19 +61,19 @@ osm_id_t osm_parse_id(const char *str) struct osm_object *osm_obj_find_by_id(enum osm_object_type type, osm_id_t id) { ASSERT(type != OSM_TYPE_INVALID && type < OSM_TYPE_MAX); - struct osm_id_to_obj *ii = osm_id_hash_find(&osm_id_hash[type], id); + struct osm_id_to_obj *ii = osm_id_hash_find(osm_this->id_hash[type], id); return ii ? ii->o : NULL; } static void *osm_obj_new(enum osm_object_type type, osm_id_t id, uns size) { ASSERT(type != OSM_TYPE_INVALID && type < OSM_TYPE_MAX); - struct osm_id_to_obj *ii = osm_id_hash_lookup(&osm_id_hash[type], id); + struct osm_id_to_obj *ii = osm_id_hash_lookup(osm_this->id_hash[type], id); if (ii->o) die("Id %ju for type %s defined twice", (uintmax_t) id, osm_obj_type_names[type]); - struct osm_object *o = mp_alloc_zero(osm_pool, size); - clist_add_tail(&osm_obj_list[type], &o->n); + struct osm_object *o = mp_alloc_zero(osm_this->pool, size); + clist_add_tail(&osm_this->obj_list[type], &o->n); o->type = type; o->id = id; clist_init(&o->tags); @@ -89,12 +86,12 @@ void osm_ref_add(struct osm_object *parent, clist *list, struct osm_object *son, { ASSERT(parent != son); - struct osm_ref *ref = mp_alloc(osm_pool, sizeof(*ref)); + struct osm_ref *ref = mp_alloc(osm_this->pool, sizeof(*ref)); ref->o = son; ref->role = role; clist_add_tail(list, &ref->n); - struct osm_ref *backref = mp_alloc(osm_pool, sizeof(*ref)); + struct osm_ref *backref = mp_alloc(osm_this->pool, sizeof(*ref)); backref->o = parent; backref->role = 0; clist_add_tail(&son->backrefs, &backref->n); @@ -135,7 +132,7 @@ struct dict osm_key_dict, osm_value_dict; void osm_obj_add_tag_raw(struct osm_object *o, osm_key_t key, osm_val_t val) { - struct osm_tag *t = mp_alloc(osm_pool, sizeof(*t)); + struct osm_tag *t = mp_alloc(osm_this->pool, sizeof(*t)); t->key = key; t->val = val; clist_add_tail(&o->tags, &t->n); @@ -199,7 +196,7 @@ void osm_node_dump(struct osm_node *n) void osm_node_dump_all(void) { printf("Known nodes:\n"); - CLIST_FOR_EACH(struct osm_node *, n, osm_obj_list[OSM_TYPE_NODE]) + CLIST_FOR_EACH(struct osm_node *, n, osm_this->obj_list[OSM_TYPE_NODE]) osm_node_dump(n); putchar('\n'); } @@ -233,7 +230,7 @@ void osm_way_dump(struct osm_way *w) void osm_way_dump_all(void) { printf("Known ways:\n"); - CLIST_FOR_EACH(struct osm_way *, w, osm_obj_list[OSM_TYPE_WAY]) + CLIST_FOR_EACH(struct osm_way *, w, osm_this->obj_list[OSM_TYPE_WAY]) osm_way_dump(w); putchar('\n'); } @@ -273,7 +270,7 @@ void osm_relation_dump(struct osm_relation *r) void osm_relation_dump_all(void) { printf("Known relations:\n"); - CLIST_FOR_EACH(struct osm_relation *, r, osm_obj_list[OSM_TYPE_RELATION]) + CLIST_FOR_EACH(struct osm_relation *, r, osm_this->obj_list[OSM_TYPE_RELATION]) osm_relation_dump(r); putchar('\n'); } @@ -296,7 +293,7 @@ void osm_multipolygon_dump(struct osm_multipolygon *m) void osm_multipolygon_dump_all(void) { printf("Known multipolygons:\n"); - CLIST_FOR_EACH(struct osm_multipolygon *, r, osm_obj_list[OSM_TYPE_MULTIPOLYGON]) + CLIST_FOR_EACH(struct osm_multipolygon *, r, osm_this->obj_list[OSM_TYPE_MULTIPOLYGON]) osm_multipolygon_dump(r); putchar('\n'); } @@ -378,7 +375,7 @@ static void mpg_walk_boundary(struct osm_multipolygon *m, bool inner) { if (!v->visited) { - struct osm_mpg_boundary *b = mp_alloc(osm_pool, sizeof(*b)); + struct osm_mpg_boundary *b = mp_alloc(osm_this->pool, sizeof(*b)); clist_add_tail(&m->boundaries, &b->n); b->inner = inner; clist_init(&b->nodes); @@ -387,7 +384,7 @@ static void mpg_walk_boundary(struct osm_multipolygon *m, bool inner) while (!w->visited) { w->visited = 1; - struct osm_ref *f = mp_alloc(osm_pool, sizeof(*f)); + struct osm_ref *f = mp_alloc(osm_this->pool, sizeof(*f)); clist_add_tail(&b->nodes, &f->n); f->o = w->o; f->role = 0; @@ -417,7 +414,7 @@ static void mpg_walk_boundary(struct osm_multipolygon *m, bool inner) if (w != v) osm_obj_warn(&mpg_current->o, "Boundary not closed at node %ju", (uintmax_t) w->o->id); - struct osm_ref *f = mp_alloc(osm_pool, sizeof(*f)); + struct osm_ref *f = mp_alloc(osm_this->pool, sizeof(*f)); clist_add_tail(&b->nodes, &f->n); f->o = v->o; f->role = 0; @@ -470,7 +467,7 @@ void osm_make_multipolygons(void) { uns mpg_cnt = 0; - CLIST_FOR_EACH(struct osm_relation *, r, osm_obj_list[OSM_TYPE_RELATION]) + CLIST_FOR_EACH(struct osm_relation *, r, osm_this->obj_list[OSM_TYPE_RELATION]) if (osm_obj_find_tag(&r->o, KEY_TYPE) == VALUE_MULTIPOLYGON) { osm_multipolygon_make(r); @@ -489,7 +486,7 @@ void osm_project(const char *spec) if (!osm_pj) die("Unable to initialize projection %s", spec); - CLIST_FOR_EACH(struct osm_node *, n, osm_obj_list[OSM_TYPE_NODE]) + CLIST_FOR_EACH(struct osm_node *, n, osm_this->obj_list[OSM_TYPE_NODE]) { projUV p; p.u = n->x * DEG_TO_RAD; @@ -561,15 +558,24 @@ bool osm_obj_center(struct osm_object *o, double *xp, double *yp) /*** Globals ***/ -void osm_init(void) +struct osm *osm_init(void) { - osm_pool = mp_new(65536); + struct mempool *mp = mp_new(65536); + struct osm *osm = mp_alloc_zero(mp, sizeof(*osm)); + osm->pool = mp; + for (int i=0; iobj_list[i]); + osm->id_hash[i] = mp_alloc(mp, sizeof(struct osm_id_hash_table)); + osm->id_hash[i]->pool = mp; + osm_id_hash_init(osm->id_hash[i]); } - osm_tag_init(); + + if (!osm_this) + osm_tag_init(); + osm_this = osm; + return osm; } void osm_dump(void) diff --git a/osm.h b/osm.h index 80d9fd2..ba240c6 100644 --- a/osm.h +++ b/osm.h @@ -77,10 +77,16 @@ struct osm_mpg_boundary { clist nodes; // List of osm_ref's (without back-references, since the boundary is not a regular object) }; -void osm_init(void); -void osm_dump(void); +struct osm { + struct mempool *pool; + clist obj_list[OSM_TYPE_MAX]; + struct osm_id_hash_table *id_hash[OSM_TYPE_MAX]; +}; + +extern struct osm *osm_this; -extern clist osm_obj_list[OSM_TYPE_MAX]; +struct osm *osm_init(void); +void osm_dump(void); osm_id_t osm_parse_id(const char *str); struct osm_object *osm_obj_find_by_id(enum osm_object_type type, osm_id_t id); @@ -161,4 +167,8 @@ enum value_names { #undef P }; +/* xml.c */ + +void osm_xml_parse(const char *name); + #endif diff --git a/xml.c b/xml.c index 98f2f8b..53caec5 100644 --- a/xml.c +++ b/xml.c @@ -168,8 +168,6 @@ static void h_etag(struct xml_context *ctx) void osm_xml_parse(const char *name) { - msg(L_INFO, "Loading %s", name); - struct xml_context ctx; xml_init(&ctx); ctx.h_warn = ctx.h_error = ctx.h_fatal = h_error; -- 2.39.2