]> mj.ucw.cz Git - leo.git/blob - style.c
Parametrized drawing of map scale
[leo.git] / style.c
1 /*
2  *      Hic Est Leo -- Styling
3  *
4  *      (c) 2014 Martin Mares <mj@ucw.cz>
5  */
6
7 #include <ucw/lib.h>
8 #include <ucw/mempool.h>
9
10 #include <stdio.h>
11
12 #include "leo.h"
13 #include "osm.h"
14 #include "style.h"
15
16 struct dict style_prop_dict, style_layer_dict;
17
18 static const char * const style_wk_props[] = {
19   NULL,
20 #define P(x,y) [PROP_##x] = y,
21 #include "dict-props.h"
22 #undef P
23   NULL
24 };
25
26 static const char * const style_wk_layers[] = {
27   NULL,
28   "default",
29   NULL
30 };
31
32 void styles_init(void)
33 {
34   dict_init(&style_prop_dict, style_wk_props);
35   dict_init(&style_layer_dict, style_wk_layers);
36 }
37
38 #define HASH_NODE struct style_prop
39 #define HASH_PREFIX(x) style_prop_##x
40 #define HASH_KEY_ATOMIC key
41 #define HASH_WANT_FIND
42 #define HASH_WANT_LOOKUP
43 #define HASH_GIVE_ALLOC
44 // FIXME: Make <ucw/hashtable.h> accept our pool
45 #define HASH_ZERO_FILL
46 #define HASH_TABLE_DYNAMIC
47 #define HASH_TABLE_ALLOC
48 #define HASH_TABLE_VARS struct mempool *pool;
49 static void *style_prop_alloc(struct style_prop_table *table, uns size);
50 static inline void style_prop_free(struct style_prop_table *table UNUSED, void *x UNUSED) { }
51 #include <ucw/hashtable.h>
52
53 static void *style_prop_alloc(struct style_prop_table *table, uns size)
54 {
55   return mp_alloc_fast(table->pool, size);
56 }
57
58 void style_init(struct style_results *r)
59 {
60   r->pool = mp_new(4096);
61   r->num_layers = dict_size(&style_layer_dict);
62   r->layers = mp_alloc_zero(r->pool, r->num_layers * sizeof(struct style_info *));
63   r->num_active_layers = 0;
64   r->active_layers = mp_alloc_zero(r->pool, r->num_layers * sizeof(layer_t));
65 }
66
67 void style_cleanup(struct style_results *r)
68 {
69   mp_delete(r->pool);
70 }
71
72 void style_begin(struct style_results *r, struct osm_object *o)
73 {
74   ASSERT(!r->num_active_layers);
75   mp_push(r->pool);
76   r->obj = o;
77 }
78
79 void style_end(struct style_results *r)
80 {
81   for (uns i=0; i<r->num_active_layers; i++)
82     r->layers[r->active_layers[i]] = NULL;
83   r->layers[0] = NULL;
84   r->num_active_layers = 0;
85   mp_pop(r->pool);
86 }
87
88 static inline void style_assign(struct style_prop *dest, struct style_prop *src)
89 {
90   dest->type = src->type;
91   dest->val = src->val;
92 }
93
94 static struct style_info *style_get_info(struct style_results *r, layer_t layer)
95 {
96   ASSERT(layer < r->num_layers);
97   if (!r->layers[layer])
98     {
99       struct style_info *si = mp_alloc_zero(r->pool, sizeof(*si));
100       r->layers[layer] = si;
101       si->hash = mp_alloc_zero(r->pool, sizeof(struct style_prop_table));
102       si->hash->pool = r->pool;
103       style_prop_init(si->hash);
104
105       if (layer != STYLE_LAYER_ALL)
106         {
107           r->active_layers[r->num_active_layers++] = layer;
108
109           // Copy all properties which have been set for all layers
110           struct style_info *si_all = r->layers[STYLE_LAYER_ALL];
111           if (si_all)
112             {
113               /*
114                * CAVEAT: This is probably wrong. When no properties are set explicitly
115                * set for a layer, all-layer properties are not propagated. Hopefully harmless.
116                */
117               HASH_FOR_ALL_DYNAMIC(style_prop, si_all->hash, s)
118                 {
119                   style_assign(style_prop_lookup(si->hash, s->key), s);
120                 }
121               HASH_END_FOR;
122             }
123         }
124     }
125   return r->layers[layer];
126 }
127
128 void style_enable_default_layer(struct style_results *r)
129 {
130   style_get_info(r, STYLE_LAYER_DEFAULT);
131 }
132
133 void style_set_by_layer(struct style_results *r, layer_t layer, struct style_prop *p)
134 {
135   if (layer == STYLE_LAYER_ALL)
136     {
137       // Set in all existing layers
138       for (uns i=0; i < r->num_active_layers; i++)
139         style_assign(style_prop_lookup(r->layers[r->active_layers[i]]->hash, p->key), p);
140       // ... and let it propagate to STYLE_LAYER_ALL
141     }
142
143   struct style_info *si = style_get_info(r, layer);
144   style_assign(style_prop_lookup(si->hash, p->key), p);
145 }
146
147 void style_set(struct style_info *si, struct style_prop *p)
148 {
149   style_assign(style_prop_lookup(si->hash, p->key), p);
150 }
151
152 struct style_prop *style_get(struct style_info *si, prop_t key)
153 {
154   return style_prop_find(si->hash, key);
155 }
156
157 struct style_prop *style_get_and_check(struct style_info *si, prop_t key, uns allowed_types)
158 {
159   struct style_prop *p = style_prop_find(si->hash, key);
160   if (!p)
161     return NULL;
162   if (!(allowed_types & (1 << p->type)))
163     {
164       // XXX: Better diagnostics?
165       msg(L_WARN, "Style property %s set to invalid type #%u", style_prop_decode(p->key), p->type);
166       return NULL;
167     }
168   return p;
169 }
170
171 osm_val_t style_get_ident(struct style_info *si, prop_t key)
172 {
173   struct style_prop *p = style_get_and_check(si, key, 1 << PROP_TYPE_IDENT);
174   return p ? p->val.id : 0;
175 }
176
177 osm_val_t style_get_string(struct style_info *si, prop_t key)
178 {
179   struct style_prop *p = style_get_and_check(si, key, (1 << PROP_TYPE_STRING) | (1 << PROP_TYPE_IDENT));
180   return p ? p->val.id : 0;
181 }
182
183 bool style_get_number(struct style_info *si, prop_t key, double *dp)
184 {
185   struct style_prop *p = style_get_and_check(si, key, 1 << PROP_TYPE_NUMBER);
186   if (!p)
187     return 0;
188   *dp = p->val.number;
189   return 1;
190 }
191
192 bool style_get_color(struct style_info *si, prop_t key, color_t *colorp)
193 {
194   struct style_prop *p = style_get_and_check(si, key, 1 << PROP_TYPE_COLOR);
195   if (!p)
196     return 0;
197   *colorp = p->val.color;
198   return 1;
199 }
200
201 void style_dump(struct style_results *r)
202 {
203   for (uns i=0; i < r->num_active_layers; i++)
204     {
205       layer_t layer = r->active_layers[i];
206       printf("Layer %s (%u)\n", style_layer_decode(layer), layer);
207       struct style_info *si = r->layers[layer];
208       HASH_FOR_ALL_DYNAMIC(style_prop, si->hash, s)
209         {
210           printf("\t");
211           style_dump_prop(s);
212         }
213       HASH_END_FOR;
214     }
215 }
216
217 static void style_dump_val(struct style_prop *s)
218 {
219   uns cnt = 0;
220
221   switch (s->type)
222     {
223     case PROP_TYPE_STRING:
224       printf("%s [string]", osm_val_decode(s->val.id));
225       break;
226     case PROP_TYPE_IDENT:
227       printf("%s [ident]", osm_val_decode(s->val.id));
228       break;
229     case PROP_TYPE_NUMBER:
230       printf("%.6g [number]", s->val.number);
231       break;
232     case PROP_TYPE_COLOR:
233       printf("%06x [color]", s->val.color);
234       break;
235     case PROP_TYPE_LIST:
236       putchar('(');
237       CLIST_FOR_EACH(struct style_val_list_entry *, e, *s->val.list)
238         {
239           if (cnt++)
240             printf(", ");
241           style_dump_val(&e->val);
242         }
243       printf(") [list]");
244       break;
245     default:
246       printf("[unknown type %u]", s->type);
247     }
248 }
249
250 void style_dump_prop(struct style_prop *s)
251 {
252   printf("%s = ", style_prop_decode(s->key));
253   style_dump_val(s);
254   putchar('\n');
255 }
256
257 void style_scale(struct style_info *si, double *wp, double *hp, prop_t width_prop, prop_t height_prop)
258 {
259   double w, h;
260   bool got_width = style_get_number(si, width_prop, &w);
261   bool got_height = style_get_number(si, height_prop, &h);
262
263   if (got_width + got_height == 2)
264     {
265       *wp = w;
266       *hp = h;
267     }
268   else if (got_width + got_height == 1)
269     {
270       if (got_width)
271         {
272           *hp *= w / *wp;
273           *wp = w;
274         }
275       else
276         {
277           *wp *= h / *hp;
278           *hp = h;
279         }
280     }
281 }