2 * Hic Est Leo -- Map Simplification
4 * (c) 2022 Martin Mares <mj@ucw.cz>
8 // #pragma GCC optimize("-O0")
13 #include <ucw/clists.h>
14 #include <ucw/mempool.h>
24 static struct mempool *simp_pool;
25 static struct osm *simp_osm;
26 static osm_id_t simp_last_id;
34 struct simp_node *snode;
38 struct osm_node *node;
39 struct simp_way_ref *prev_on_way;
40 struct simp_way_ref *next_on_way;
47 byte raw_coords[sizeof(struct coords)];
52 static void simp_hash_init_data(struct simp_node *s)
54 clist_init(&s->way_refs);
57 #define HASH_NODE struct simp_node
58 #define HASH_PREFIX(x) simp_hash_##x
59 #define HASH_KEY_MEMORY raw_coords
60 #define HASH_KEY_SIZE sizeof(struct coords)
61 #define HASH_WANT_LOOKUP
62 #define HASH_GIVE_INIT_DATA
63 #define HASH_USE_POOL simp_pool
64 #define HASH_TABLE_ALLOC
65 #include <ucw/hashtable.h>
67 static struct simp_node *simp_lookup_node(struct osm_node *n)
69 struct coords c = { .x = n->x, .y = n->y };
70 return simp_hash_lookup((byte *) &c);
73 static void simp_register_symbol(struct symbol *sym, z_index_t zindex)
75 struct osm_object *o = sym->o;
80 simp_lookup_node((struct osm_node *) o);
84 struct osm_way *w = (struct osm_way *) o;
85 struct simp_way_ref *wr_last = NULL;
86 struct osm_node *prev_n = NULL;
89 for (uint i=0; i<2; i++)
91 struct osm_node *n = (struct osm_node *) (i ? osm_ref_head(&w->nodes) : osm_ref_tail(&w->nodes));
92 struct sym_point *sp = sym_point_new(&n->o);
93 sp->shape = VALUE_CIRCLE;
95 sp->fill_color = 0x0000ff;
102 if (clist_size(&w->nodes) < 2)
105 OSM_FOR_EACH_BEGIN(struct osm_node *, n, w->nodes)
110 struct simp_node *s = simp_lookup_node(n);
111 struct simp_way_ref *wref = mp_alloc(simp_pool, sizeof(*wref));
114 wref->zindex = zindex;
117 wref->prev_on_way = wr_last;
118 wref->next_on_way = NULL;
120 wr_last->next_on_way = wref;
122 wref->merge_done = 0;
123 clist_add_tail(&s->way_refs, &wref->n);
131 die("Simplify: Unsupported symbol type %u", o->type);
135 static struct simp_way_ref *wref_other_end(struct simp_way_ref *wr)
139 while (wr->prev_on_way)
140 wr = wr->prev_on_way;
144 while (wr->next_on_way)
145 wr = wr->next_on_way;
150 static struct simp_way_ref *wref_only_other(struct simp_node *sn, struct simp_way_ref *in_wr)
152 struct simp_way_ref *out_wr = NULL;
154 CLIST_FOR_EACH(struct simp_way_ref *, wr, sn->way_refs)
167 /*** Merging of ways ***/
169 static struct simp_way_ref **merge_wrefs;
170 static uint num_merged_ways, num_merged_segments;
172 static void simp_merge_way(struct simp_node *s)
174 // XXX: This is grossly over-simplified. We assume that every way generates
175 // at most one symbol, which is definitely not the case for ways rendered
176 // with casing. But it should be sufficient for now.
178 uint nrefs = clist_size(&s->way_refs);
182 struct simp_way_ref *wr1, *wr2, *wr;
183 wr1 = clist_head(&s->way_refs);
184 wr2 = clist_tail(&s->way_refs);
185 if (!(!wr1->prev_on_way != !wr1->next_on_way && !wr2->prev_on_way != !wr2->next_on_way))
187 if (wr1->merge_done || wr2->merge_done)
191 DBG("Merge: Starting with wr %p", wr);
196 struct simp_way_ref *or = wref_other_end(wr);
197 struct simp_node *on = or->snode;
199 struct simp_way_ref *cr = wref_only_other(on, or);
200 DBG("XXX: wr=%p or=%p cr=%p", wr, or, cr);
201 if (!cr || !sym_same_attrs_p(or->sym, cr->sym))
203 DBG("Merge: Back stop at %p", cr);
207 DBG("Merge: Back to %p", cr);
212 DBG("Merge: Loop detected");
217 // Now, we are at the beginning/end of a single way
219 DBG("Merge: Back to %p", wr);
220 wr = wref_other_end(wr);
221 DBG("Merge: Other end is %p", wr);
222 GARY_RESIZE(merge_wrefs, 0);
223 *GARY_PUSH(merge_wrefs) = wr;
228 struct simp_way_ref *or = wref_other_end(wr);
229 struct simp_node *on = or->snode;
231 struct simp_way_ref *cr = wref_only_other(on, or);
232 if (!cr || !sym_same_attrs_p(or->sym, cr->sym))
234 DBG("Merge: Fwd stop at %p", cr);
238 DBG("Merge: Fwd to %p", cr);
239 *GARY_PUSH(merge_wrefs) = cr;
243 if (GARY_SIZE(merge_wrefs) < 2)
249 struct osm_way *nw = osm_way_new(++simp_last_id);
250 struct symbol *main_sym = NULL;
252 for (uint i=0; i < GARY_SIZE(merge_wrefs); i++)
255 clist_remove(&wr->n);
258 osm_way_add_node(nw, wr->node);
260 main_sym->o = &nw->o;
263 sym_disable(wr->sym);
267 while (wr = wr->prev_on_way)
269 clist_remove(&wr->n);
270 osm_way_add_node(nw, wr->node);
275 // ASSERT(wr->next_on_way);
276 while (wr = wr->next_on_way)
278 clist_remove(&wr->n);
279 osm_way_add_node(nw, wr->node);
283 num_merged_segments++;
286 // osm_obj_dump(&nw->o);
287 simp_register_symbol(main_sym, wr1->zindex);
288 // ((struct sym_line *) main_sym)->color = 0x0000ff;
291 static void simp_merge_ways(void)
293 HASH_FOR_ALL(simp_hash, s)
299 msg(L_INFO, "Simplify: Merged %u segments to %u new ways", num_merged_segments, num_merged_ways);
302 /*** Splitting of ways ***/
304 static struct simp_way_ref **split_breakpoints;
305 static uint num_split_ways, num_split_segments;
307 static void simp_split_way(struct simp_way_ref *wr)
309 GARY_RESIZE(split_breakpoints, 0);
310 for (struct simp_way_ref *tr=wr; tr; tr=tr->next_on_way)
311 if (tr->prev_on_way && tr->next_on_way)
313 struct simp_node *sn = tr->snode;
314 struct simp_way_ref *x = clist_head(&sn->way_refs);
315 if (x && clist_next(&sn->way_refs, &x->n))
316 *GARY_PUSH(split_breakpoints) = tr;
319 uint num_bp = GARY_SIZE(split_breakpoints);
323 DBG("Split: Want to split wr %p (%u times)", wr, num_bp);
324 // ((struct sym_line *) wr->sym)->color = 0x0000ff;
328 struct symbol *orig_sym = wr->sym;
329 struct symbol *sym = NULL;
330 struct osm_way *w = NULL;
332 for (struct simp_way_ref *tr=wr; tr; tr=tr->next_on_way)
334 clist_remove(&tr->n);
337 w = osm_way_new(++simp_last_id);
338 sym = sym_clone(orig_sym);
341 osm_way_add_node(w, tr->node);
342 if (bp < num_bp && split_breakpoints[bp] == tr)
344 sym_plan(sym, wr->zindex);
345 num_split_segments++;
354 num_split_segments++;
355 sym_plan(sym, wr->zindex);
356 simp_register_symbol(sym, wr->zindex);
359 sym_disable(orig_sym);
362 static void simp_split_ways(void)
364 HASH_FOR_ALL(simp_hash, s)
366 struct simp_way_ref *wr, *tmp;
367 CLIST_WALK_DELSAFE(wr, s->way_refs, tmp)
368 if (!wr->prev_on_way && wr->next_on_way)
373 msg(L_INFO, "Simplify: Split %u ways to %u segments", num_split_ways, num_split_segments);
378 msg(L_INFO, "Simplifying symbol topology");
379 simp_pool = mp_new(65536);
380 simp_osm = osm_init();
381 GARY_INIT_ALLOC(merge_wrefs, 0, &simp_pool->allocator);
382 GARY_INIT_ALLOC(split_breakpoints, 0, &simp_pool->allocator);
385 sym_for_all_planned(simp_register_symbol);
389 mp_delete(simp_pool);