7 #include <ucw/mempool.h>
12 #include "lab-utils.h"
13 #include "lab-bitmaps.h"
14 #include "lab-lines.h"
16 #define BLOCK_SIZE 4096
27 // List of lines (osm_ways) making up a logical line
31 struct graph_edge *first;
38 struct graph_edge **edges;
39 int num; // Used for debug, mostly debug prints
44 osm_id_t id; // Actual line (osm_way) ID
45 struct sym_line *line;
48 z_index_t zindex; // z-index of label
50 int visited; // Iteration when line was last visited with BFS
51 uns longline; // Logical line this line was made part of
52 enum edge_dir dir; // Direction with respect to logical line, used by BFS
53 struct graph_node *n1; // Actual line endpoints
54 struct graph_node *n2;
55 struct graph_edge *prev; // Neighbouring lines in logical line
56 struct graph_edge *next;
57 int num; // Used for debug
60 #define HASH_NODE struct graph_node
61 #define HASH_PREFIX(x) hash_##x
62 #define HASH_KEY_ATOMIC id
63 #define HASH_WANT_FIND
65 #define HASH_WANT_CLEANUP
66 #include <ucw/hashtable.h>
68 static void bfs(uns longline);
69 static void bfs_edge(struct graph_edge *e, struct graph_node *node, struct graph_node *anode, enum edge_dir dir);
71 static void make_graph(void);
72 static void label_graph(void);
73 static void make_segments(void);
74 static void make_sections(void);
76 static void cut_edge(struct graph_edge *e, double dist);
77 static struct request_line *make_new_line(void);
78 static struct request_section *make_new_section(struct request_line *rl);
79 static struct request_segment *make_new_segment(struct request_section *rls, struct symbol *sym);
82 static int num_edges = 0;
83 static int dbg_num_hits = 0;
85 static struct graph_edge **bfs_queue;
87 double conf_max_section_length = 80, conf_max_section_overlay = 10;
89 static struct request_line *make_new_line(void)
91 struct request_line *rl = GARY_PUSH(requests_line);
92 rl->request.ind = num_requests++;
93 rl->request.type = REQUEST_LINE;
94 GARY_INIT(rl->sections, 0);
95 GARY_INIT(rl->request.variants, 0);
100 static struct request_section *make_new_section(struct request_line *rl)
102 struct request_section *rls = GARY_PUSH(rl->sections);
103 rls->request.ind = num_requests++;
104 rls->request.type = REQUEST_SECTION;
105 GARY_INIT(rls->segments, 0);
106 GARY_INIT(rls->request.variants, 0);
111 static struct request_segment *make_new_segment(struct request_section *rls, struct symbol *sym)
113 struct request_segment *rs = GARY_PUSH(rls->segments);
115 rs->request.ind = num_requests++;
116 rs->request.type = REQUEST_SEGMENT;
118 GARY_INIT(rs->request.variants, 0);
121 struct variant *v = GARY_PUSH(rs->request.variants);
128 static void make_graph(void)
131 struct mempool *mp_edges = mp_new(BLOCK_SIZE);
133 DEBUG(dbg_graph, VERBOSITY_GENERAL, "Extracting nodes, will iterate over %zu ways\n", GARY_SIZE(buffer_line));
134 for (uns i=0; i<GARY_SIZE(buffer_line); i++)
136 struct osm_way *way = (struct osm_way *) buffer_line[i].line->s.o;
137 struct graph_node *g_prev = NULL;
138 struct osm_node *o_prev = NULL;
140 CLIST_FOR_EACH(struct osm_ref *, ref, way->nodes)
142 // FIXME: Shall osm_object's type be checked here?
143 struct osm_node *o_node = (struct osm_node *) ref->o;
145 struct graph_node *g_node = hash_find(ref->o->id);
148 g_node = hash_new(ref->o->id);
149 GARY_INIT(g_node->edges, 0);
151 g_node->id = ref->o->id;
152 g_node->num = num_nodes++;
162 struct graph_edge *e = mp_alloc(mp_edges, sizeof(struct graph_edge));
163 e->num = num_edges++;
164 e->id = buffer_line[i].line->s.o->id;
165 e->color = buffer_line[i].line->color;
166 e->length = hypot(abs(o_prev->x - o_node->x), abs(o_prev->y - o_node->y));
172 e->longline = (uns) -1;
173 e->line = buffer_line[i].line;
177 struct graph_edge **edge = GARY_PUSH(g_prev->edges);
179 edge = GARY_PUSH(g_node->edges);
188 void dump_graph(void)
190 HASH_FOR_ALL(hash, node)
192 printf("* Node: (%d) #%ju [%.2f; %.2f]\n", node->num, node->id, node->o->x, node->o->y);
193 for (uns i=0; i<GARY_SIZE(node->edges); i++)
195 struct graph_edge *e = node->edges[i];
196 printf("\t edge (%d) #%ju to ", e->num, e->id);
197 if (node->edges[i]->n1->id == node->id)
198 printf("(%d) #%ju [%.2f; %.2f]\n", e->n2->num, e->n2->id, e->n2->o->x, e->n2->o->y);
199 else if (node->edges[i]->n2->id == node->id)
200 printf("(%d) #%ju [%.2f; %.2f]\n", e->n1->num, e->n1->id, e->n1->o->x, e->n1->o->y);
203 // This shouldn't ever happen
204 printf("BEWARE! Edge is associated with a node it doesn't belongs to!\n");
209 if ((node->edges[i]->label) && (node->edges[i]->label->type == SYMBOLIZER_TEXT)) printf(" labelled %s;", osm_val_decode(((struct sym_text *) node->edges[i]->label)->text));
210 else if ((node->edges[i]->label)) printf("Labelled\n");
212 printf(" colored %d;", node->edges[i]->color);
213 printf(" length %.2f", node->edges[i]->length);
220 static void label_graph(void)
222 DEBUG(dbg_graph, VERBOSITY_GENERAL, "There are %zu line labels requested\n", GARY_SIZE(buffer_linelabel));
223 for (uns i=0; i<GARY_SIZE(buffer_linelabel); i++)
225 if (buffer_linelabel[i].label->type == SYMBOLIZER_TEXT)
226 DEBUG(dbg_graph, VERBOSITY_INDIVIDUAL, "Labelling nodes of way %s\n", osm_val_decode(((struct sym_text *) buffer_linelabel[i].label)->text));
227 CLIST_FOR_EACH(struct osm_ref *, ref, buffer_linelabel[i].way->nodes)
229 DEBUG(dbg_graph, VERBOSITY_PLACEMENT, "Looking for node %ju\n", ref->o->id);
230 struct graph_node *n = hash_find(ref->o->id);
233 printf("BEWARE! Requested node couldn't be found.\n");
237 DEBUG(dbg_graph, VERBOSITY_ALL, "Searching among %zu edges\n", GARY_SIZE(n->edges));
238 for (uns j=0; j<GARY_SIZE(n->edges); j++)
240 if (n->edges[j]->id == buffer_linelabel[i].way->o.id)
242 DEBUG(dbg_graph, VERBOSITY_ALL, "Labelling node %ju\n", n->id);
243 n->edges[j]->label = buffer_linelabel[i].label;
244 n->edges[j]->zindex = buffer_linelabel[i].zindex;
252 static void bfs_edge(struct graph_edge *e, struct graph_node *node, struct graph_node *anode, enum edge_dir dir)
254 DEBUG(dbg_bfs, VERBOSITY_PLACEMENT, "BFS edge called for edge %d (going %d) in direction %d\n", e->num, e->dir, dir);
255 struct graph_edge *candidate = NULL;
257 for (uns i=0; i<GARY_SIZE(node->edges); i++)
259 struct graph_edge *other = node->edges[i];
260 if ((other->longline != (uns) -1) && (other->longline != e->longline)) continue;
262 if ((uns) other->visited != e->longline) {
263 DEBUG(dbg_bfs, VERBOSITY_PLACEMENT, "Pushing new edge %d / %ju\n", other->num, other->id);
264 struct graph_edge **e_ptr = GARY_PUSH(bfs_queue);
266 other->visited = e->longline;
269 if (((other->n1->id == node->id) && (other->n2->id == anode->id)) ||
270 ((other->n2->id == node->id) && (other->n1->id == anode->id)))
273 if (((other->n1->id == node->id) || (other->n2->id == node->id)) &&
274 (e->label) && (other->label) &&
275 (sym_look_same(e->label, other->label)))
277 if (! candidate || (other->length > candidate->length))
284 DEBUG(dbg_bfs, VERBOSITY_PLACEMENT, "New line in longline %u\n", e->longline);
285 struct graph_edge *other = candidate;
286 other->longline = e->longline;
288 if (((dir == DIR_BWD) && (other->n1->id == node->id)) ||
289 ((dir == DIR_FWD) && (other->n2->id == node->id)))
291 struct graph_node *swp = other->n2;
292 other->n2 = other->n1;
301 longlines[other->longline].first = other;
314 static void bfs(uns longline)
316 DEBUG(dbg_bfs, VERBOSITY_INDIVIDUAL, "BFS called for longline %u\n", longline);
317 DEBUG(dbg_bfs, VERBOSITY_INDIVIDUAL, "%zu longlines exist\n", GARY_SIZE(longlines));
319 for (uns i=0; i<GARY_SIZE(bfs_queue); i++)
321 struct graph_edge *cur = bfs_queue[i];
322 DEBUG(dbg_bfs, VERBOSITY_PLACEMENT, "Exploring new edge %d; %zu remaining\n", cur->num, GARY_SIZE(bfs_queue));
324 cur->visited = longline;
326 if (cur->longline == (uns) -1)
329 if (cur->dir == DIR_UNSET)
331 cur->dir = DIR_CENTER;
332 bfs_edge(cur, cur->n1, cur->n2, DIR_BWD);
333 bfs_edge(cur, cur->n2, cur->n1, DIR_FWD);
340 bfs_edge(cur, cur->n1, cur->n2, cur->dir);
343 bfs_edge(cur, cur->n2, cur->n1, cur->dir);
353 static void make_sections(void)
355 GARY_INIT(bfs_queue, 0);
356 GARY_INIT(longlines, 0);
358 HASH_FOR_ALL(hash, node)
360 for (uns i=0; i<GARY_SIZE(node->edges); i++)
362 if ((node->edges[i]->label) && (node->edges[i]->longline == (uns) -1))
364 GARY_PUSH(longlines);
365 longlines[GARY_SIZE(longlines)-1].first = node->edges[i];
367 DEBUG(dbg_bfs, VERBOSITY_INDIVIDUAL, "Running new BFS\n");
368 DEBUG(dbg_bfs, VERBOSITY_INDIVIDUAL, "Creating longline %zu\n", GARY_SIZE(longlines)-1);
370 GARY_RESIZE(bfs_queue, 0);
371 struct graph_edge **e = GARY_PUSH(bfs_queue);
373 node->edges[i]->longline = GARY_SIZE(longlines)-1;
374 bfs(node->edges[i]->longline);
376 DEBUG(dbg_bfs, VERBOSITY_INDIVIDUAL, "Joined %d edges\n", dbg_num_hits); dbg_num_hits = 0;
377 DEBUG(dbg_bfs, VERBOSITY_INDIVIDUAL, "Planned %zu edges\n", GARY_SIZE(bfs_queue));
383 GARY_FREE(bfs_queue);
386 static void cut_edge(struct graph_edge *e, double dist)
388 DEBUG(dbg_segments, VERBOSITY_PLACEMENT, "Cutting [%.2f; %.2f] -- [%.2f; %.2f] to dist %.2f\n", e->n1->o->x, e->n1->o->y, e->n2->o->x, e->n2->o->y, dist);
390 struct graph_edge *new = xmalloc(sizeof(struct graph_edge));
394 new->label = sym_copy(e->label);
396 struct osm_node *n1 = e->n1->o;
397 struct osm_node *n2 = e->n2->o;
399 if ((n1->x == n2->x) && (n1->y == n2->y))
401 printf("[%.2f; %.2f] -- [%.2f; %.2f]\n", n1->x, n1->y, n2->x, n2->y);
402 DEBUG(dbg_segments, VERBOSITY_PLACEMENT, "Won't cut point\n");
406 // BEWARE: This creates new OSM object and modifies original data
407 // FIXME: Though this doesn't crash anything now, it could become deathly curse one day
408 struct osm_node *n11 = xmalloc(sizeof(struct osm_node));
409 struct graph_node *gn = xmalloc(sizeof(struct graph_node));
411 double vsize = hypot(n1->x - n2->x, n1->y - n2->y);
412 n11->x = n1->x + (n2->x - n1->x) / vsize * dist;
413 n11->y = n1->y + (n2->y - n1->y) / vsize * dist;
415 e->n2 = new->n1 = gn;
417 e->length = hypot(abs(n1->x - n11->x), abs(n1->y - n11->y));
418 new->length = hypot(abs(n11->x - n2->x), abs(n11->y - n2->y));
422 static void make_segments(void)
424 for (uns i=0; i<GARY_SIZE(longlines); i++)
426 // Skip lines which are not labelled
427 if (! (longlines[i].first && longlines[i].first->label))
430 struct request_line *request = make_new_line();
431 struct request_section *rls = make_new_section(request);
432 struct request_segment *rs = NULL;
434 struct graph_edge *e = longlines[i].first;
435 double cur_length = 0;
437 struct sym_text *st = NULL;
438 if (e->label->type == SYMBOLIZER_TEXT)
440 st = (struct sym_text *) e->label;
444 // FIXME: Should other label types be supported in future?
445 DEBUG(dbg_segments, VERBOSITY_PLACEMENT, "Warning: Skipping line\n");
449 DEBUG(dbg_segments, VERBOSITY_INDIVIDUAL, "New longline\n");
455 DEBUG(dbg_segments, VERBOSITY_PLACEMENT, "BEWARE: Edge cycle\n");
460 DEBUG(dbg_segments, VERBOSITY_PLACEMENT, "Taking edge from [%.2f; %.2f] to [%.2f; %.2f] of length %.2f\n", e->n1->o->x, e->n1->o->y, e->n2->o->x, e->n2->o->y, e->length);
462 if (st && (e->length < st->tw))
465 DEBUG(dbg_segments, VERBOSITY_PLACEMENT, "Warning: Skipping segment\n");
469 if (cur_length + e->length > conf_max_section_length + conf_max_section_overlay)
471 DEBUG(dbg_segments, VERBOSITY_PLACEMENT, "Edge too long, length is %.2f; %.2f - %.2f = %.2f\n", e->length, conf_max_section_length, cur_length, conf_max_section_length - cur_length);
472 // HACK to prevent cutting to 0 lenght
473 cut_edge(e, max2(conf_max_section_length - cur_length, 2));
476 rs = make_new_segment(rls, NULL);
477 rs->label = xmalloc(sizeof(struct sym_text));
478 *((struct sym_text *) rs->label) = *((struct sym_text *) e->label);
480 rs->x1 = e->n1->o->x;
481 rs->y1 = e->n1->o->y;
482 rs->x2 = e->n2->o->x;
483 rs->y2 = e->n2->o->y;
485 if (fabs(rs->x2 - rs->x1) > 0.01)
487 rs->slope = (rs->y2 - rs->y1) / (rs->x2 - rs->x1);
488 // This works a little bit magically :)
489 // It's possible not to care about quadrants as it "just works" as expected
490 ((struct sym_text *) rs->label)->rotate = convert_to_deg(atan(rs->slope));
494 rs->slope = 142; // Magic!
495 ((struct sym_text *) rs->label)->rotate = 1;
497 struct variant *v = GARY_PUSH(rs->request.variants);
498 make_bitmap(v, rs->label);
500 rs->zindex = e->zindex;
502 cur_length += e->length;
503 if (cur_length > conf_max_section_length)
505 DEBUG(dbg_segments, VERBOSITY_PLACEMENT, "Making new section, new length would be %f, allowed is %.2f / %.2f\n", cur_length + e->length, conf_max_section_length, conf_max_section_overlay);
507 rls = make_new_section(request);
514 if (GARY_SIZE(request->sections[0].segments) == 0)
516 DEBUG(dbg_segments, VERBOSITY_INDIVIDUAL, "WARNING: Longline without any segment, skipped\n");
518 struct request_section *rls = &request->sections[0];
519 GARY_FREE(rls->segments);
520 GARY_FREE(rls->request.variants);
522 struct request_line *rl = &requests_line[GARY_SIZE(requests_line)-1];
523 GARY_FREE(rl->sections);
524 GARY_FREE(rl->request.variants);
526 GARY_POP(requests_line);
532 void segment_lines(void)
540 void lines_cleanup(void)
545 void dump_longlines(void)
547 printf("*** Longlines dump\n");
548 for (uns i=0; i<GARY_SIZE(longlines); i++)
550 printf("Longline %u:", i);
551 struct graph_edge *e = longlines[i].first;
552 if ((e->label) && (e->label->type == SYMBOLIZER_TEXT))
553 printf(" labelled %s", osm_val_decode(((struct sym_text *) e->label)->text));
558 printf("\t#%ju (%d): [%.2f; %.2f] -- [%.2f; %.2f] (dir %d)\n",
559 e->id, e->num, e->n1->o->x, e->n1->o->y, e->n2->o->x, e->n2->o->y, e->dir);