]> mj.ucw.cz Git - leo.git/blob - sym.c
334568161c24f007a86936f6cf816e03fc567331
[leo.git] / sym.c
1 /*
2  *      Hic Est Leo -- Symbols
3  *
4  *      (c) 2014 Martin Mares <mj@ucw.cz>
5  */
6
7 #include <ucw/lib.h>
8 #include <ucw/gary.h>
9 #include <ucw/mempool.h>
10 #include <ucw/stkstring.h>
11
12 #include <stdio.h>
13
14 #include "leo.h"
15 #include "osm.h"
16 #include "style.h"
17 #include "sym.h"
18
19 #undef CLAMP            // FIXME: Fix in libucw?
20 #define CLAMP(x,min,max) ({ typeof(x) _t=x; (_t < min) ? min : (_t > max) ? max : _t; })        /** Clip a number @x to interval [@min,@max] **/
21
22 static struct symbolizer *symbolizers[] = {
23   [SYMBOLIZER_INVALID] = NULL,
24   [SYMBOLIZER_POINT] = &symbolizer_point,
25   [SYMBOLIZER_ICON] = &symbolizer_icon,
26   [SYMBOLIZER_LINE] = &symbolizer_line,
27   [SYMBOLIZER_AREA] = &symbolizer_area,
28   [SYMBOLIZER_TEXT] = &symbolizer_text,
29   [SYMBOLIZER_LINEIMG] = &symbolizer_lineimg,
30 };
31
32 struct mempool *sym_mp;
33
34 struct sym_planned {
35   struct symbol *sym;
36   z_index_t zindex;
37 };
38
39 static struct sym_planned *sym_planned;
40
41 static inline bool sym_before(struct sym_planned *x, struct sym_planned *y)
42 {
43   COMPARE_LT(x->zindex, y->zindex);
44   COMPARE_LT(x->sym->o->type, y->sym->o->type);
45   COMPARE_LT(x->sym->o->id, y->sym->o->id);
46   return 0;
47 }
48
49 #define ASORT_PREFIX(x) sym_##x
50 #define ASORT_KEY_TYPE struct sym_planned
51 #define ASORT_LT(_x,_y) sym_before(&(_x), &(_y))
52 #include <ucw/sorter/array-simple.h>
53
54 void sym_init(void)
55 {
56   sym_mp = mp_new(65536);
57   GARY_INIT(sym_planned, 0);
58
59   for (uns i = SYMBOLIZER_INVALID + 1; i < SYMBOLIZER_MAX; i++)
60     if (symbolizers[i]->init)
61       (*symbolizers[i]->init)();
62 }
63
64 void *sym_new(enum symbolizer_type type, struct osm_object *o, size_t size)
65 {
66   struct symbol *s = mp_alloc_zero(sym_mp, size);
67   s->type = type;
68   s->o = o;
69   return s;
70 }
71
72 void sym_plan(struct symbol *sym, z_index_t zindex)
73 {
74   // DEBUG
75   if (sym->type == SYMBOLIZER_TEXT)
76   {
77     struct sym_text *st = (struct sym_text *) sym;
78     printf("In planner: Planning text %s at [%.2f; %.2f]\n", osm_val_decode(st->text), st->x, st->y);
79   }
80
81   struct sym_planned *p = GARY_PUSH(sym_planned);
82   p->sym = sym;
83   p->zindex = zindex;
84   if (debug_dump_symbols)
85     printf("--> planning symbol <%s> with z-index %u for %s\n",
86       symbolizers[sym->type]->name, zindex, STK_OSM_NAME(sym->o));
87 }
88
89 z_index_t sym_zindex(struct osm_object *o, struct style_info *si, double default_mzi)
90 {
91   double zi = 0;
92   style_get_number(si, PROP_Z_INDEX, &zi);
93   double zi2 = CLAMP(zi, -100, 100);
94   if (zi2 != zi)
95     osm_obj_warn(o, "z-index clipped from %.6g to %.6g", zi, zi2);
96
97 #if 0
98   // FIXME: object-z-index not used yet
99   double ozi = 0;
100   style_get_number(si, PROP_OBJECT_Z_INDEX, &ozi);
101   double ozi2 = CLAMP(ozi, -100, 100);
102   if (ozi2 != ozi)
103     osm_obj_warn(o, "object-z-index clipped from %.6g to %.6g", ozi, ozi2);
104 #endif
105
106   double mzi = default_mzi;
107   if (mzi == 2)
108     {
109       // FIXME: This is a terrible hack.
110       style_get_number(si, PROP_CASING_MAJOR_Z_INDEX, &mzi);
111     }
112   else if (mzi == 4.9 || mzi == 5)
113     {
114       // FIXME: This is another terrible hack.
115       style_get_number(si, PROP_TEXT_MAJOR_Z_INDEX, &mzi);
116     }
117   else
118     style_get_number(si, PROP_MAJOR_Z_INDEX, &mzi);
119   double mzi2 = CLAMP(mzi, -100, 100);
120   if (mzi2 != mzi)
121     osm_obj_warn(o, "major-z-index clipped from %.6g to %.6g", mzi, mzi2);
122
123   return (z_index_t)(10000 + (z_index_t)(zi2 * 100) + 10000*( 10000 + (z_index_t)(mzi2 * 100) ));
124 }
125
126 void sym_from_style(struct osm_object *o, struct style_results *sr, struct svg *svg)
127 {
128   for (uns i=0; i < sr->num_active_layers; i++)
129     {
130       for (uns j = SYMBOLIZER_INVALID + 1; j < SYMBOLIZER_MAX; j++)
131         if (symbolizers[j]->gen)
132           (symbolizers[j]->gen)(o, sr->layers[sr->active_layers[i]], svg);
133     }
134 }
135
136 static void sym_draw(struct symbol *sym, z_index_t zindex, struct svg *svg)
137 {
138   ASSERT(sym->type && sym->type < SYMBOLIZER_MAX);
139   if (debug_dump_symbols)
140     printf("Drawing symbol <%s> at z-index %u for %s\n", symbolizers[sym->type]->name, zindex, STK_OSM_NAME(sym->o));
141   symbolizers[sym->type]->draw(sym, svg);
142 }
143
144 void sym_draw_all(struct svg *svg)
145 {
146   for (uns i = 0; i < GARY_SIZE(sym_planned); i++)
147   {
148     // DEBUG
149     if (sym_planned[i].sym->type == SYMBOLIZER_TEXT)
150     {
151       struct sym_text *st = (struct sym_text *) sym_planned[i].sym;
152       printf("In planner: Will draw text %s at [%.2f; %.2f]\n", osm_val_decode(st->text), st->x, st->y);
153     }
154   }
155
156   msg(L_INFO, "Sorting %u symbols by depth", (uns) GARY_SIZE(sym_planned));
157   sym_sort(sym_planned, GARY_SIZE(sym_planned));
158
159   msg(L_INFO, "Dumping icon library");
160   svg_icon_dump_library(svg);
161
162   msg(L_INFO, "Drawing symbols");
163   for (uns i = 0; i < GARY_SIZE(sym_planned); i++)
164   {
165     // DEBUG
166     if (sym_planned[i].sym->type == SYMBOLIZER_TEXT)
167     {
168       struct sym_text *st = (struct sym_text *) sym_planned[i].sym;
169       printf("In planner: Will draw text %s at [%.2f; %.2f]\n", osm_val_decode(st->text), st->x, st->y);
170     }
171
172     sym_draw(sym_planned[i].sym, sym_planned[i].zindex, svg);
173   }
174 }