2 * Hic Est Leo -- Map Simplification
4 * (c) 2022 Martin Mares <mj@ucw.cz>
7 // #pragma GCC optimize("-O0")
12 #include <ucw/clists.h>
13 #include <ucw/mempool.h>
23 static struct mempool *simp_pool;
24 static struct osm *simp_osm;
25 static osm_id_t simp_last_id;
33 struct simp_node *snode;
36 struct osm_node *node;
37 struct simp_way_ref *prev_on_way;
38 struct simp_way_ref *next_on_way;
45 byte raw_coords[sizeof(struct coords)];
50 static void simp_hash_init_data(struct simp_node *s)
52 clist_init(&s->way_refs);
55 #define HASH_NODE struct simp_node
56 #define HASH_PREFIX(x) simp_hash_##x
57 #define HASH_KEY_MEMORY raw_coords
58 #define HASH_KEY_SIZE sizeof(struct coords)
59 #define HASH_WANT_LOOKUP
60 #define HASH_GIVE_INIT_DATA
61 #define HASH_USE_POOL simp_pool
62 #define HASH_TABLE_ALLOC
63 #include <ucw/hashtable.h>
65 static struct simp_node *simp_lookup_node(struct osm_node *n)
67 struct coords c = { .x = n->x, .y = n->y };
68 return simp_hash_lookup((byte *) &c);
71 static void simp_register_symbol(struct symbol *sym)
73 struct osm_object *o = sym->o;
78 simp_lookup_node((struct osm_node *) o);
82 struct osm_way *w = (struct osm_way *) o;
83 struct simp_way_ref *wr_last = NULL;
84 struct osm_node *prev_n = NULL;
87 for (uint i=0; i<2; i++)
89 struct osm_node *n = (struct osm_node *) (i ? osm_ref_head(&w->nodes) : osm_ref_tail(&w->nodes));
90 struct sym_point *sp = sym_point_new(&n->o);
91 sp->shape = VALUE_CIRCLE;
93 sp->fill_color = 0x0000ff;
100 if (clist_size(&w->nodes) < 2)
103 OSM_FOR_EACH_BEGIN(struct osm_node *, n, w->nodes)
108 struct simp_node *s = simp_lookup_node(n);
109 struct simp_way_ref *wref = mp_alloc(simp_pool, sizeof(*wref));
114 wref->prev_on_way = wr_last;
115 wref->next_on_way = NULL;
117 wr_last->next_on_way = wref;
119 wref->merge_done = 0;
120 clist_add_tail(&s->way_refs, &wref->n);
128 die("Simplify: Unsupported symbol type %u", o->type);
132 static struct simp_way_ref *wref_other_end(struct simp_way_ref *wr)
136 while (wr->prev_on_way)
137 wr = wr->prev_on_way;
141 while (wr->next_on_way)
142 wr = wr->next_on_way;
147 static struct simp_way_ref *wref_only_other(struct simp_node *sn, struct simp_way_ref *in_wr)
149 struct simp_way_ref *out_wr = NULL;
151 CLIST_FOR_EACH(struct simp_way_ref *, wr, sn->way_refs)
164 static struct simp_way_ref **merge_wrefs;
165 static uint simp_merged_ways, simp_merged_segments;
167 static void simp_merge_way(struct simp_node *s)
169 // XXX: This is grossly over-simplified. We assume that every way generates
170 // at most one symbol, which is definitely not the case for ways rendered
171 // with casing. But it should be sufficient for now.
173 uint nrefs = clist_size(&s->way_refs);
177 struct simp_way_ref *wr1, *wr2, *wr;
178 wr1 = clist_head(&s->way_refs);
179 wr2 = clist_tail(&s->way_refs);
180 if (!(!wr1->prev_on_way != !wr1->next_on_way && !wr2->prev_on_way != !wr2->next_on_way))
182 if (wr1->merge_done || wr2->merge_done)
186 DBG("Merge: Starting with wr %p", wr);
191 struct simp_way_ref *or = wref_other_end(wr);
192 struct simp_node *on = or->snode;
194 struct simp_way_ref *cr = wref_only_other(on, or);
195 DBG("XXX: wr=%p or=%p cr=%p", wr, or, cr);
196 if (!cr || !sym_same_attrs_p(or->sym, cr->sym))
198 DBG("Merge: Back stop at %p", cr);
202 DBG("Merge: Back to %p", cr);
207 DBG("Merge: Loop detected");
212 // Now, we are at the beginning/end of a single way
214 DBG("Merge: Back to %p", wr);
215 wr = wref_other_end(wr);
216 DBG("Merge: Other end is %p", wr);
217 GARY_RESIZE(merge_wrefs, 0);
218 *GARY_PUSH(merge_wrefs) = wr;
223 struct simp_way_ref *or = wref_other_end(wr);
224 struct simp_node *on = or->snode;
226 struct simp_way_ref *cr = wref_only_other(on, or);
227 if (!cr || !sym_same_attrs_p(or->sym, cr->sym))
229 DBG("Merge: Fwd stop at %p", cr);
233 DBG("Merge: Fwd to %p", cr);
234 *GARY_PUSH(merge_wrefs) = cr;
238 if (GARY_SIZE(merge_wrefs) < 2)
244 struct osm_way *nw = osm_way_new(++simp_last_id);
245 struct symbol *main_sym = NULL;
247 for (uint i=0; i < GARY_SIZE(merge_wrefs); i++)
250 clist_remove(&wr->n);
253 osm_way_add_node(nw, wr->node);
255 main_sym->o = &nw->o;
258 sym_disable(wr->sym);
262 while (wr = wr->prev_on_way)
264 clist_remove(&wr->n);
265 osm_way_add_node(nw, wr->node);
270 // ASSERT(wr->next_on_way);
271 while (wr = wr->next_on_way)
273 clist_remove(&wr->n);
274 osm_way_add_node(nw, wr->node);
278 simp_merged_segments++;
281 // osm_obj_dump(&nw->o);
282 simp_register_symbol(main_sym);
283 // ((struct sym_line *) main_sym)->color = 0x0000ff;
286 static void simp_merge_ways(void)
288 HASH_FOR_ALL(simp_hash, s)
294 msg(L_INFO, "Simplify: Merged %u segments to %u new ways", simp_merged_segments, simp_merged_ways);
299 msg(L_INFO, "Simplifying symbol topology");
300 simp_pool = mp_new(65536);
301 simp_osm = osm_init();
302 GARY_INIT_ALLOC(merge_wrefs, 0, &simp_pool->allocator);
305 sym_for_all_planned(simp_register_symbol);
308 mp_delete(simp_pool);