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)
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)
{
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);
#include <ucw/conf.h>
#include <ucw/gary.h>
#include <ucw/mempool.h>
+#include <ucw/simple-lists.h>
#include <stdio.h>
#include <math.h>
#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;
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 {
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
}
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)
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
+}
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"
# Draw blue border around the requested rectangle
DrawBorder 0
- # MapCSS stylesheet to apply
- StyleSheet poskole.css
-
# Write SVG output here
SVGOutput output.svg
}
#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;
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
#include "leo.h"
#include "osm.h"
-static struct mempool *osm_pool;
+struct osm *osm_this;
/*** Generic objects ***/
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",
#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 <ucw/hashtable.h>
-static struct osm_id_hash_table osm_id_hash[OSM_TYPE_MAX];
-
osm_id_t osm_parse_id(const char *str)
{
uintmax_t id;
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);
{
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);
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);
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');
}
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');
}
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');
}
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');
}
{
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);
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;
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;
{
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);
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;
/*** 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; i<OSM_TYPE_MAX; i++)
{
- clist_init(&osm_obj_list[i]);
- osm_id_hash_init(&osm_id_hash[i]);
+ clist_init(&osm->obj_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)
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);
#undef P
};
+/* xml.c */
+
+void osm_xml_parse(const char *name);
+
#endif
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;