1 
2 /**
3  * @file labels.c
4  * This file contains functions for label and label candidate manipulation
5 */
6 #include "labels.h"
7 static int label_skyline(FT_Face face, const char *charset, label_t * label);
8 static struct line_pnts *box_trans_rot(struct bound_box * bb, label_point_t * p,
9 				       double angle);
10 static void label_point_candidates(label_t * label);
11 static void label_line_candidates(label_t * label);
12 static int candidate_compare(const void *a, const void *b);
13 static double label_avedist(label_t * label, label_candidate_t * candidate);
14 static double label_flatness(label_t * label, label_candidate_t * candidate);
15 static double label_pointover(label_t * label, label_candidate_t * candidate);
16 static double label_lineover(label_t * label, label_candidate_t * candidate,
17 			     int linetype);
18 static double min_dist_2_lines(struct line_pnts *skyline,
19 			       struct line_pnts *swathline,
20 			       label_point_t * p);
21 static int box_overlap(struct bound_box * a, struct bound_box * b);
22 static int box_overlap2(struct line_pnts *a, struct line_pnts *b);
23 
24 /**
25  * The font size in map units. A global variable because I'm lazy :P
26  */
27 static double font_size = 0.0;
28 
29 /**
30  * The ideal distance, that is the distance between the base line of a label and a line feature.
31  */
32 static double ideal_distance;
33 
34 /**The vector Map structure*/
35 static struct Map_info Map;
36 
37 /**
38  * The size of the buffer around features where labels should never be
39  */
40 static double buffer = 0.0;
41 
labels_init(struct params * p,int * n_labels)42 label_t *labels_init(struct params *p, int *n_labels)
43 {
44     label_t *labels;
45     int legal_types, layer, i = 0, error, sql_len;
46     size_t label_sz;
47     struct field_info *fi;
48     dbDriver *driver;
49     FT_Library library;
50     FT_Face face;
51     struct GFONT_CAP *font_cap;
52 
53     fprintf(stderr, "Initialising labels...");
54     legal_types = Vect_option_to_types(p->type);
55 
56     /* open vector for read only */
57     if (Vect_open_old(&Map, p->map->answer, "") < 0)
58 	G_fatal_error(_("Unable to open vector map <%s>"), p->map->answer);
59 
60     label_sz = Vect_get_num_primitives(&Map, legal_types);
61 
62     G_debug(1, "Need to allocate %lu bytes of memory",
63 	    sizeof(label_t) * label_sz);
64     labels = (label_t *) G_malloc(sizeof(label_t) * label_sz);
65     G_debug(1, "labels=%p", labels);
66 
67     if (labels == NULL)
68 	G_fatal_error(_("Cannot allocate %lu bytes of memory"),
69 		      sizeof(label_t) * label_sz);
70 
71     /* open database */
72     layer = atoi(p->layer->answer);
73     fi = Vect_get_field(&Map, layer);
74     if (fi == NULL)
75 	G_fatal_error(_("Unable to get layer info for vector map"));
76     driver = db_start_driver_open_database(fi->driver, fi->database);
77     if (driver == NULL)
78 	G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
79 		      fi->database, fi->driver);
80     db_set_error_handler_driver(driver);
81 
82     sql_len = strlen(p->column->answer) + strlen(fi->table) +
83 	strlen(fi->key) + 30;
84 
85     /* initialize FT 2 library */
86     if (FT_Init_FreeType(&library))
87 	G_fatal_error(_("Unable to initialise FreeType"));
88     font_cap = find_font_from_freetypecap(p->font->answer);
89     if (font_cap == NULL)
90 	G_fatal_error(_("Unable to find font '%s'\n"), p->font->answer);
91     if (font_cap->type != GFONT_FREETYPE)
92 	G_fatal_error(_("Font '%s' is not a FreeType font\n"),
93 		      p->font->answer);
94     error = FT_New_Face(library, font_cap->path, 0, &face);
95     if (error == FT_Err_Unknown_File_Format)
96 	G_fatal_error(_("Font file format is not supported by FreeType"));
97     else if (error)
98 	G_fatal_error(_("Font file can not be loaded"));
99     p->font->answer = G_store(font_cap->name);
100     free_freetypecap(font_cap);
101 
102     font_size = atof(p->size->answer);
103     buffer = atof(p->isize->answer);
104 
105     /* use 1 point = 1 map unit */
106     if (FT_Set_Char_Size(face, (int)((font_size) * 64.0), 0, 100, 100))
107 	G_fatal_error(_("Unable to set font size"));
108 
109     /* start reading the map */
110     while (1) {
111 	struct line_pnts *Points;
112 	struct line_cats *Cats;
113 
114 	dbCursor cursor;
115 	dbTable *table;
116 	dbColumn *column;
117 	dbString query, value;
118 
119 	int type, cat, more, nrows;
120 	char *sql;
121 
122 	if (i == label_sz) {	/* we need more memory */
123 	    label_sz += 100;
124 	    G_debug(1, "Need to resize %p to %lu bytes of memory",
125 		    (void *)labels, sizeof(label_t) * label_sz);
126 	    labels = G_realloc(labels, sizeof(label_t) * label_sz);
127 	    if (labels == NULL) {
128 		G_fatal_error(_("Cannot allocate more memory"));
129 	    }
130 	}
131 
132 	G_percent(i, label_sz, 10);
133 
134 	memset(&labels[i], 0, sizeof(label_t));
135 
136 	Points = Vect_new_line_struct();
137 	Cats = Vect_new_cats_struct();
138 
139 	type = Vect_read_next_line(&Map, Points, Cats);
140 	if (type == -1)
141 	    G_fatal_error(_("Unable to read vector map"));
142 	if (type == -2)
143 	    break;		/* EOF */
144 	if (!(legal_types & type))
145 	    continue;
146 
147 	Vect_cat_get(Cats, layer, &cat);
148 	if (cat < 0)
149 	    continue;		/* no cat for this field */
150 
151 	sql = (char *) G_malloc(sql_len);
152 	/* Read label from database */
153 	sprintf(sql, "select %s from %s where %s = %d", p->column->answer,
154 		fi->table, fi->key, cat);
155 	G_debug(3, "SQL: %s", sql);
156 	db_init_string(&query);
157 	db_set_string(&query, sql);
158 	G_free(sql);
159 
160 	if (db_open_select_cursor(driver, &query, &cursor, DB_SEQUENTIAL) !=
161 	    DB_OK)
162 	    G_fatal_error(_("Unable to select attributes"));
163 	db_free_string(&query);
164 	nrows = db_get_num_rows(&cursor);
165 	if (nrows < 1) {
166 	    G_warning(_("No record for category %d in table <%s>"), cat,
167 		      fi->table);
168 	    continue;
169 	}
170 
171 	if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK || !more)
172 	    continue;
173 
174 	table = db_get_cursor_table(&cursor);
175 	column = db_get_table_column(table, 0);	/* first column */
176 
177 	db_init_string(&value);
178 	db_convert_column_value_to_string(column, &value);
179 	db_close_cursor(&cursor);
180 
181 	G_debug(3, "Label: %s", db_get_string(&value));
182 
183 	/* ignore empty strings */
184 	if (strlen(db_get_string(&value)) == 0)
185 	    continue;
186 
187 	labels[i].text = G_store(db_get_string(&value));
188 	labels[i].cat = cat;
189 	labels[i].type = type;
190 	labels[i].shape = Points;
191 	G_debug(3, "Label [%d]: %s, cat=%d, type=0x%02x", i, labels[i].text,
192 		labels[i].cat, labels[i].type);
193 
194 	/* make a skyline for the text */
195 	label_skyline(face, p->charset->answer, &labels[i]);
196 
197 	i++;
198 
199 	db_free_string(&value);
200 	/*              Vect_destroy_line_struct(Points); */
201 	Vect_destroy_cats_struct(Cats);
202     }
203 
204     {
205 	FT_UInt glyph_index;
206 
207 	glyph_index = FT_Get_Char_Index(face, 'X');
208 	if (FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT))
209 	    G_fatal_error("Cannot determine ideal height");
210 	ideal_distance = 0.3 * face->glyph->metrics.height / 64.0;
211     }
212 
213     FT_Done_Face(face);
214     FT_Done_FreeType(library);
215     db_close_database_shutdown_driver(driver);
216     /*      Vect_close(&Map); */
217     G_percent(label_sz, label_sz, 10);
218 
219     *n_labels = i;
220     return labels;
221 
222 }
223 
224 /**
225  * This function calculates the skyline of a label and stores it in the label structure.
226  * @param face The openned FT library face to use.
227  * @param The charset to use
228  * @param The label to which we want to create a skyline
229  */
label_skyline(FT_Face face,const char * charset,label_t * label)230 static int label_skyline(FT_Face face, const char *charset, label_t * label)
231 {
232     int i, len;
233     double advance = 0.0;
234 
235     len = strlen(label->text);
236     label->skyline = Vect_new_line_struct();
237     G_debug(3, "Creating skyline for '%s'", label->text);
238 
239     for (i = 0; i < len; i++) {
240 	FT_UInt glyph_index;
241 
242 	glyph_index = FT_Get_Char_Index(face, label->text[i]);
243 	if (FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT))
244 	    G_warning(_("Cannot load glyph for '%c'"), label->text[i]);
245 
246 	/* insert the 4 corners of the bounding box */
247 	{
248 	    label_point_t top_left, top_right, bottom_right, bottom_left;
249 
250 	    G_debug(5,
251 		    "horiBearingX=%ld horiBearingY=%ld width=%ld height=%ld advance=%ld",
252 		    face->glyph->metrics.horiBearingX,
253 		    face->glyph->metrics.horiBearingY,
254 		    face->glyph->metrics.width, face->glyph->metrics.height,
255 		    face->glyph->metrics.horiAdvance);
256 
257 	    top_left.x = advance;
258 	    top_left.y = face->glyph->metrics.horiBearingY / 64.0;
259 
260 	    top_right.x = advance + face->glyph->metrics.horiAdvance / 64.0;
261 	    top_right.y = face->glyph->metrics.horiBearingY / 64.0;
262 
263 	    bottom_right.x =
264 		advance + face->glyph->metrics.horiAdvance / 64.0;
265 	    bottom_right.y =
266 		(face->glyph->metrics.horiBearingY -
267 		 face->glyph->metrics.height) / 64.0;
268 
269 	    bottom_left.x = advance;
270 	    bottom_left.y = (face->glyph->metrics.horiBearingY -
271 			     face->glyph->metrics.height) / 64.0;
272 
273 	    if (i == 0) {
274 		G_debug(5, "Character(%d) '%c': Adding UL point (%lf,%lf)",
275 			i, label->text[i], top_left.x, top_left.y);
276 		Vect_append_point(label->skyline, top_left.x, top_left.y,
277 				  0.0);
278 		G_debug(5, "Character(%d) '%c': Adding UR point (%lf,%lf)", i,
279 			label->text[i], top_right.x, top_right.y);
280 		Vect_append_point(label->skyline, top_right.x, top_right.y,
281 				  0.0);
282 
283 		G_debug(5, "Character(%d) '%c': Adding LR point (%lf,%lf)",
284 			i, label->text[i], bottom_right.x, bottom_right.y);
285 		Vect_append_point(label->skyline,
286 				  bottom_right.x, bottom_right.y, 0.0);
287 
288 		G_debug(5, "Character(%d) '%c': Adding LL point (%lf,%lf)",
289 			i, label->text[i], bottom_left.x, bottom_left.y);
290 		Vect_append_point(label->skyline,
291 				  bottom_left.x, bottom_left.y, 0.0);
292 		Vect_append_point(label->skyline, top_left.x, top_left.y,
293 				  0.0);
294 	    }
295 	    else {
296 		G_debug(5, "Character(%d) '%c': Adding UL point (%lf,%lf)",
297 			i, label->text[i], top_left.x, top_left.y);
298 		Vect_line_insert_point(label->skyline, i * 2,
299 				       top_left.x, top_left.y, 0.0);
300 		G_debug(5, "Character(%d) '%c': Adding UR point (%lf,%lf)",
301 			i, label->text[i], top_right.x, top_right.y);
302 		Vect_line_insert_point(label->skyline, i * 2 + 1,
303 				       top_right.x, top_right.y, 0.0);
304 
305 		G_debug(5, "Character(%d) '%c': Adding LR point (%lf,%lf)",
306 			i, label->text[i], bottom_right.x, bottom_right.y);
307 		Vect_line_insert_point(label->skyline, i * 2 + 2,
308 				       bottom_right.x, bottom_right.y, 0.0);
309 
310 		G_debug(5, "Character(%d) '%c': Adding LL point (%lf,%lf)",
311 			i, label->text[i], bottom_left.x, bottom_left.y);
312 		Vect_line_insert_point(label->skyline, i * 2 + 3,
313 				       bottom_left.x, bottom_left.y, 0.0);
314 	    }
315 
316 	    advance += face->glyph->metrics.horiAdvance / 64.0;
317 	    G_debug(5, "Total advance  %lf", advance);
318 	}
319     }
320     /* remove duplicate points */
321     Vect_line_prune(label->skyline);
322     /* get the boundingbox */
323     Vect_line_box(label->skyline, &label->bb);
324     return 1;
325 }
326 
327 /**
328  * This function generates label candidates for each label.
329  * @param labels The array of labels to generate candidate places for.
330  * @param n_labels The size of the array.
331  */
label_candidates(label_t * labels,int n_labels)332 void label_candidates(label_t * labels, int n_labels)
333 {
334     int i;
335 
336     /* generate candidate location for each label based on feture type
337      * see chapter 5 of MERL-TR-96-04 */
338     fprintf(stderr, "Generating label candidates: ...");
339     for (i = 0; i < n_labels; i++) {
340 	G_percent(i, n_labels - 1, 1);
341 	switch (labels[i].type) {
342 	case GV_POINT:
343 	    G_debug(3, "Line (%d): %s", i, labels[i].text);
344 	    label_point_candidates(&labels[i]);
345 	    break;
346 	case GV_LINE:
347 	    G_debug(3, "Line (%d): %s", i, labels[i].text);
348 	    label_line_candidates(&labels[i]);
349 	    break;
350 	    /*                case GV_AREA:
351 	     * label_area_candidates(labels[i]);
352 	     * break; */
353 	default:
354 	    /* this should never be reached */
355 	    break;
356 	}
357     }
358     Vect_close(&Map);
359     return;
360 }
361 
362 /**
363  * This function generates candidates for point features.
364  * @param label. The point label to which we want to create label candidates.
365  */
label_point_candidates(label_t * label)366 static void label_point_candidates(label_t * label)
367 {
368     double height, width;
369     int i;
370     label_candidate_t *candidates;
371 
372     candidates = G_calloc(19, sizeof(label_candidate_t));
373     if (candidates == NULL) {
374 	G_fatal_error("Cannot allocate memory.");
375     }
376 
377     height = label->bb.N - label->bb.S;
378     width = label->bb.E - label->bb.W;
379     /* 2 upper left-hand side labels are placed so that they are
380      * 1/3 and 2/3 of label height above point, and right aligned */
381     candidates[0].point.x = label->shape->x[0] - width - buffer * 0.75;
382     candidates[0].point.y = label->shape->y[0] + (5.0 / 9.0) * height;
383     candidates[0].score = 0.63;
384 
385     candidates[1].point.x = label->shape->x[0] - width - buffer * 0.85;
386     candidates[1].point.y = label->shape->y[0] + (1.0 / 3.0) * height;
387     candidates[1].score = 0.44;
388     /* same height as label point */
389     candidates[2].point.x = label->shape->x[0] - width - buffer * 0.95;
390     candidates[2].point.y = label->shape->y[0];
391     candidates[2].score = 0.07;
392     /* 3 lower left-hand side labels are placed so that they are
393      * 1/3, 2/3 and 3/3 of label height below point, and right aligned */
394     candidates[3].point.x = label->shape->x[0] - width - buffer * 0.95;
395     candidates[3].point.y = label->shape->y[0] - (1.0 / 3.0) * height;
396     candidates[3].score = 0.10;
397 
398     candidates[4].point.x = label->shape->x[0] - width - buffer * 0.95;
399     candidates[4].point.y = label->shape->y[0] - (5.0 / 9.0) * height;
400     candidates[4].score = 0.02;
401 
402     candidates[5].point.x = label->shape->x[0] - width - buffer * 0.95;
403     candidates[5].point.y = label->shape->y[0] - height;
404     candidates[5].score = 0.37;
405 
406     /* 2 upper right-hand side labels are placed so that they are
407      * 1/3 and 2/3 of label height above point*/
408     candidates[6].point.x = label->shape->x[0] + buffer * 0.85;
409     candidates[6].point.y = label->shape->y[0] + (5.0 / 9.0) * height;
410     candidates[6].score = 0.41;
411 
412     candidates[7].point.x = label->shape->x[0] + buffer * 0.95;
413     candidates[7].point.y = label->shape->y[0] + (1.0 / 3.0) * height;
414     candidates[7].score = 0.33;
415     /* same height as label point */
416     candidates[8].point.x = label->shape->x[0] + buffer;
417     candidates[8].point.y = label->shape->y[0];
418     candidates[8].score = 0.00;
419     /* 4 lower left-hand side labels are placed so that they are
420      * 1/4, 2/4 3/4 and 4/4 of label height below point*/
421     candidates[9].point.x = label->shape->x[0] + buffer;
422     candidates[9].point.y = label->shape->y[0] - 0.25 * height;
423     candidates[9].score = 0.04;
424 
425     candidates[10].point.x = label->shape->x[0] + buffer;
426     candidates[10].point.y = label->shape->y[0] - 0.5 * height;
427     candidates[10].score = 0.3;
428 
429     candidates[11].point.x = label->shape->x[0] + buffer;
430     candidates[11].point.y = label->shape->y[0] - 0.75 * height;
431     candidates[11].score = 0.12;
432 
433     candidates[12].point.x = label->shape->x[0] + buffer;
434     candidates[12].point.y = label->shape->y[0] - height;
435     candidates[12].score = 0.59;
436 
437     /* 3 labels above, centered, centered on left 1/3 and centered
438      * on right 1/3 of the label */
439     candidates[13].point.x = label->shape->x[0] - (1.0 / 3.0) * width;
440     candidates[13].point.y = label->shape->y[0] + fabs(label->bb.S) + buffer;
441     candidates[13].score = 0.70;
442 
443     candidates[14].point.x = label->shape->x[0] - 0.5 * width;
444     candidates[14].point.y = label->shape->y[0] + fabs(label->bb.S) + buffer;
445     candidates[14].score = 0.89;
446 
447     candidates[15].point.x = label->shape->x[0] - (2.0 / 3.0) * width;
448     candidates[15].point.y = label->shape->y[0] + fabs(label->bb.S) + buffer;
449     candidates[15].score = 0.74;
450 
451     /* 3 labels below, centered, centered on left 1/3 and centered
452      * on right 1/3 of the label */
453     candidates[16].point.x = label->shape->x[0] - (1.0 / 3.0) * width;
454     candidates[16].point.y = label->shape->y[0] - height - buffer;
455     candidates[16].score = 0.74;
456 
457     candidates[17].point.x = label->shape->x[0] - 0.5 * width;
458     candidates[17].point.y = label->shape->y[0] - height - buffer;
459     candidates[17].score = 0.89;
460 
461     candidates[18].point.x = label->shape->x[0] - (2.0 / 3.0) * width;
462     candidates[18].point.y = label->shape->y[0] - height - buffer;
463     candidates[18].score = 1.0;
464 
465     for (i = 0; i < 19; i++) {
466 	candidates[i].score += 10.0 * label_pointover(label, &candidates[i]);
467 	candidates[i].score += 15.0 * label_lineover(label, &candidates[i],
468 						     GV_LINE);
469 	G_debug(5, "calling label_lineover('%s', %d)", label->text, i);
470 	candidates[i].score += 10.0 * label_lineover(label, &candidates[i],
471 						     GV_BOUNDARY);
472 	candidates[i].rotation = 0;
473     }
474 
475     /* randomly choose one candidate to be the current */
476     label->current_candidate = (int)(19.0 * (rand() / (RAND_MAX + 1.0)));
477     label->candidates = candidates;
478     label->n_candidates = 19;
479 }
480 
481 /**
482  * This function generates label candidates for a line feature.
483  * @param label The label for which to create the candidates.
484  */
label_line_candidates(label_t * label)485 static void label_line_candidates(label_t * label)
486 {
487     double height, width, inc, length, pos;
488     label_candidate_t *above_candidates, *below_candidates, *candidates;
489     int i, n, n_c;
490 
491     height = label->bb.N - label->bb.S;
492     width = label->bb.E - label->bb.W;
493     inc = width / 8.0;
494     length = Vect_line_length(label->shape);
495 
496     n = (int)(length / inc);
497     if (n == 0) {
498 	/* treat the line as a point feature */
499 	struct line_pnts *tmp, *tmp_shape;
500 	double x, y;
501 
502 	tmp = Vect_new_line_struct();
503 	Vect_point_on_line(label->shape, length / 2.0, &x, &y,
504 			   NULL, NULL, NULL);
505 	Vect_append_point(tmp, x, y, 0);
506 	tmp_shape = label->shape;
507 	label->shape = tmp;
508 
509 	label_point_candidates(label);
510 	label->shape = tmp_shape;
511 	Vect_destroy_line_struct(tmp);
512 
513 	return;
514     }
515     above_candidates = G_calloc(n, sizeof(label_candidate_t));
516     below_candidates = G_calloc(n, sizeof(label_candidate_t));
517     if ((above_candidates == NULL) || (below_candidates == NULL)) {
518 	G_fatal_error("Cannot allocate memory.");
519     }
520 
521     /* find all candidate labels */
522     for (pos = width / 2.0, i = 0; pos < (length - 1.5 * width); pos += inc) {
523 	label_point_t p1, p2, minimum_above_distance_p,
524 	    minimum_below_distance_p;
525 	int seg1, seg2, j;
526 	struct line_pnts *above_skyline, *below_skyline, *baseline;
527 	double above_distance = 0.0, below_distance = 0.0,
528 	    minimum_above_distance = 0.0, minimum_below_distance = 0.0, angle;
529 	double flatness, centerdness;
530 
531 	seg1 =
532 	    Vect_point_on_line(label->shape, pos, &p1.x, &p1.y, NULL, NULL,
533 			       NULL);
534 	seg2 =
535 	    Vect_point_on_line(label->shape, pos + width, &p2.x, &p2.y, NULL,
536 			       NULL, NULL);
537 
538 	G_debug(1, "pos=%lf i=%d p1 at (%lf,%lf), p2 at (%lf,%lf)",
539 		pos, i, p1.x, p1.y, p2.x, p2.y);
540 
541 	angle = atan2((p2.y - p1.y), (p2.x - p1.x));
542 
543 	if ((angle > M_PI / 2) || (angle < -M_PI / 2)) {
544 	    /* turn label around 180 degrees if it would be upside down */
545 	    double tmp;
546 
547 	    tmp = p1.x;
548 	    p1.x = p2.x;
549 	    p2.x = tmp;
550 
551 	    tmp = p1.y;
552 	    p1.y = p2.y;
553 	    p2.y = tmp;
554 
555 	    if (angle < 0)
556 		angle += M_PI;
557 	    else
558 		angle -= M_PI;
559 	}
560 
561 	/* find the maximum above_distance and below_distance from the swath
562 	 * "diagonal" to determine maximum deviation from a straight line
563 	 * create the swath lines at the same time.
564 	 */
565 	above_candidates[i].swathline = Vect_new_line_struct();
566 	below_candidates[i].swathline = Vect_new_line_struct();
567 	if ((above_candidates[i].swathline == NULL) ||
568 	    (below_candidates[i].swathline == NULL))
569 	    G_fatal_error("Cannot allocate memory!");
570 	Vect_append_point(above_candidates[i].swathline, p1.x, p1.y, 0);
571 	Vect_append_point(below_candidates[i].swathline, p1.x, p1.y, 0);
572 
573 	baseline = Vect_new_line_struct();
574 	Vect_append_point(baseline, p1.x, p1.y, 0);
575 	Vect_append_point(baseline, p2.x, p2.y, 0);
576 
577 	Vect_append_point(above_candidates[i].swathline, p1.x, p1.y, 0);
578 	Vect_append_point(below_candidates[i].swathline, p1.x, p1.y, 0);
579 
580 	for (j = seg1 + 1; j < seg2; j++) {
581 	    double x, y, d;
582 
583 	    Vect_line_distance(baseline, label->shape->x[j],
584 			       label->shape->y[j], 0, 0,
585 			       &x, &y, NULL, &d, NULL, NULL);
586 	    if (label->shape->y[j] < y) {
587 		/* swathline is beneath the "diagonal" */
588 		if (d > below_distance) {
589 		    below_distance = d;
590 		}
591 	    }
592 	    else {
593 		/* swatline is above or on the "diagonal" */
594 		if (d > above_distance) {
595 		    above_distance = d;
596 		}
597 	    }
598 	    Vect_append_point(above_candidates[i].swathline,
599 			      label->shape->x[j], label->shape->y[j], 0);
600 	    Vect_append_point(below_candidates[i].swathline,
601 			      label->shape->x[j], label->shape->y[j], 0);
602 	}
603 
604 	Vect_append_point(above_candidates[i].swathline, p2.x, p2.y, 0);
605 	Vect_append_point(below_candidates[i].swathline, p2.x, p2.y, 0);
606 	Vect_destroy_line_struct(baseline);
607 
608 	if (above_distance == 0.0) {
609 	    above_distance = height - label->bb.N;
610 	}
611 	if (below_distance == 0.0) {
612 	    below_distance = height - label->bb.S;
613 	}
614 
615 	/* place a skyline at above_distance above line, and
616 	 * below_distance + height below line */
617 	{
618 	    label_point_t tp;
619 
620 	    tp.x = p1.x - above_distance * sin(angle);
621 	    tp.y = p1.y + above_distance * cos(angle);
622 	    above_skyline = skyline_trans_rot(label->skyline, &tp, angle);
623 	    tp.x = p1.x + (below_distance + height) * sin(angle);
624 	    tp.y = p1.y - (below_distance + height) * cos(angle);
625 	    below_skyline = skyline_trans_rot(label->skyline, &tp, angle);
626 	}
627 	/* find minimum distance between swath line and skylines */
628 	minimum_above_distance = min_dist_2_lines(above_skyline,
629 						  above_candidates[i].
630 						  swathline,
631 						  &minimum_above_distance_p);
632 	minimum_below_distance =
633 	    min_dist_2_lines(below_skyline, below_candidates[i].swathline,
634 			     &minimum_below_distance_p);
635 
636 	/* adjust skylines so that the minimum distance is equal to the ideal
637 	 * distance (= 0.3 * glyph height of capital X) */
638 	above_distance += ideal_distance - minimum_above_distance;
639 	below_distance += ideal_distance - minimum_below_distance;
640 
641 	Vect_destroy_line_struct(above_skyline);
642 	Vect_destroy_line_struct(below_skyline);
643 
644 	above_candidates[i].point.x = p1.x - above_distance * sin(angle);
645 	above_candidates[i].point.y = p1.y + above_distance * cos(angle);
646 
647 	below_candidates[i].point.x =
648 	    p1.x + (below_distance + height) * sin(angle);
649 	below_candidates[i].point.y =
650 	    p1.y - (below_distance + height) * cos(angle);
651 
652 	G_debug(1, "above at (%lf,%lf) below at (%lf,%lf)",
653 		above_candidates[i].point.x, above_candidates[i].point.y,
654 		below_candidates[i].point.x, below_candidates[i].point.y);
655 
656 	above_candidates[i].above = 1;
657 	below_candidates[i].above = 0;
658 	above_candidates[i].rotation = angle;
659 	below_candidates[i].rotation = angle;
660 
661 	above_candidates[i].score = 0.0;
662 	below_candidates[i].score = 0.0;
663 	/* AveDist */
664 	above_candidates[i].score +=
665 	    label_avedist(label, &above_candidates[i]);
666 	below_candidates[i].score +=
667 	    label_avedist(label, &below_candidates[i]);
668 
669 	/* flatness */
670 	flatness = label_flatness(label, &above_candidates[i]);
671 	above_candidates[i].score += flatness;
672 	flatness = label_flatness(label, &below_candidates[i]);
673 	below_candidates[i].score += flatness;
674 
675 	/* centerdness */
676 	centerdness = 3.0 * fabs(2.0 * pos / length - 1.0);
677 	above_candidates[i].score += centerdness;
678 	below_candidates[i].score += centerdness;
679 
680 	/* PointOver */
681 	above_candidates[i].score += 10.0 *
682 	    label_pointover(label, &above_candidates[i]);
683 	below_candidates[i].score += 10.0 *
684 	    label_pointover(label, &below_candidates[i]);
685 
686 	/* LineOver */
687 	above_candidates[i].lineover = 15.0 *
688 	    label_lineover(label, &above_candidates[i], GV_LINE);
689 	above_candidates[i].score += above_candidates[i].lineover;
690 
691 	below_candidates[i].lineover = 15.0 *
692 	    label_lineover(label, &below_candidates[i], GV_LINE);
693 	below_candidates[i].score += below_candidates[i].lineover;
694 
695 	/* AreaOver */
696 	above_candidates[i].score += 10.0 *
697 	    label_lineover(label, &above_candidates[i], GV_BOUNDARY);
698 	below_candidates[i].score += 10.0 *
699 	    label_lineover(label, &below_candidates[i], GV_BOUNDARY);
700 
701 	/* aboveness */
702 	below_candidates[i].score += 1.25;
703 
704 	i++;
705     }
706     n = i;
707 
708     if (n == 0) {
709 	/* treat the line as a point feature */
710 	struct line_pnts *tmp, *tmp_shape;
711 	double x, y;
712 
713 	tmp = Vect_new_line_struct();
714 	Vect_point_on_line(label->shape, length / 2.0, &x, &y,
715 			   NULL, NULL, NULL);
716 	Vect_append_point(tmp, x, y, 0);
717 	tmp_shape = label->shape;
718 	label->shape = tmp;
719 
720 	label_point_candidates(label);
721 	label->shape = tmp_shape;
722 	Vect_destroy_line_struct(tmp);
723 	return;
724     }
725 
726     candidates = G_calloc(n * 2, sizeof(label_candidate_t));
727     for (i = 0; i < n; i++) {
728 	memcpy(&candidates[i * 2], &above_candidates[i],
729 	       sizeof(label_candidate_t));
730 	memcpy(&candidates[i * 2 + 1], &below_candidates[i],
731 	       sizeof(label_candidate_t));
732     }
733     G_free(above_candidates);
734     G_free(below_candidates);
735 
736     n_c = n * 2;
737     /* pick the 32 best candidates */
738     qsort(candidates, n_c, sizeof(label_candidate_t), candidate_compare);
739 
740     if (n_c > 32) {
741 	label_candidate_t *tmp;
742 
743 	for (i = 32; i < n; i++) {
744 	    Vect_destroy_line_struct(candidates[i].baseline);
745 	    Vect_destroy_line_struct(candidates[i].swathline);
746 	}
747 
748 	tmp = G_realloc(candidates, sizeof(label_candidate_t) * 32);
749 	if (tmp != NULL) {
750 	    candidates = tmp;
751 	}
752 	n_c = 32;
753     }
754     label->current_candidate =
755 	(int)((double)(n_c) * (rand() / (RAND_MAX + 1.0)));
756     label->candidates = candidates;
757     label->n_candidates = n_c;
758 }
759 
760 /**
761  * This function compares two label candidates scores and determines which is better.
762  * @param a Candidate A
763  * @param b Candidate B
764  * @return -1 if candidate a has a lower score then candidate b. = if the
765  * scores are equal, and 1 if candidate a has a higher score then candidate b.
766  */
candidate_compare(const void * a,const void * b)767 static int candidate_compare(const void *a, const void *b)
768 {
769     const label_candidate_t *ca = a, *cb = b;
770 
771     if (ca->score < cb->score) {
772 	return -1;
773     }
774     else if (ca->score == cb->score) {
775 	return 0;
776     }
777     else {
778 	return 1;
779     }
780 }
781 
skyline_trans_rot(struct line_pnts * skyline,label_point_t * p,double angle)782 struct line_pnts *skyline_trans_rot(struct line_pnts *skyline,
783 				    label_point_t * p, double angle)
784 {
785     int i;
786     struct line_pnts *Points;
787 
788     Points = Vect_new_line_struct();
789 
790     for (i = 0; i < skyline->n_points; i++) {
791 	double x, y;
792 
793 	x = skyline->x[i] * cos(angle) - skyline->y[i] * sin(angle);
794 	y = skyline->x[i] * sin(angle) + skyline->y[i] * cos(angle);
795 	Vect_append_point(Points, x + p->x, y + p->y, 0);
796     }
797 
798     return Points;
799 }
800 
801 /**
802  * This function rotates and translates the label bounding box to the
803  * given point, and returns it as a polygon.
804  * @param bb The bounding box to translate and rotate.
805  * @param p The point to translate the bounding box to
806  * @param angle The angle (in radians) to rotate the label counter-clockwise
807  * @return A lint_pnts structure containing the rotated and translated
808  * bounding box as a polygon.
809  */
box_trans_rot(struct bound_box * bb,label_point_t * p,double angle)810 static struct line_pnts *box_trans_rot(struct bound_box * bb, label_point_t * p,
811 				       double angle)
812 {
813     struct line_pnts *Points;
814     double x0, y0, x1, y1, x2, y2;
815 
816     Points = Vect_new_line_struct();
817 
818     /* Lower Left, no rotation needed */
819     x0 = p->x + bb->W;
820     y0 = p->y + bb->S;
821     Vect_append_point(Points, x0, y0, 0);
822     /* Lower Right */
823     x1 = (bb->E - bb->W) * cos(angle);
824     y1 = (bb->E - bb->W) * sin(angle);
825     Vect_append_point(Points, x0 + x1, y0 + y1, 0);
826 
827     /* Upper Right */
828     x2 = (bb->N - bb->S) * sin(angle);
829     y2 = (bb->N - bb->S) * cos(angle);
830     /* First translate to LR, and then translate like UL */
831     Vect_append_point(Points, x0 + x1 - x2, y0 + y1 + y2, 0);
832 
833     /* Upper Left */
834     Vect_append_point(Points, x0 - x2, y0 + y2, 0);
835 
836     /* close polygon */
837     Vect_append_point(Points, x0, y0, 0);
838 
839     return Points;
840 }
841 
842 /**
843  * This function calculates the AveDist metric for line label candidates
844  * @param label The label to which candidate belongs to.
845  * @candidate The candidate of which we are to calculate the metric.
846  * @return The metric;
847  */
label_avedist(label_t * label,label_candidate_t * candidate)848 static double label_avedist(label_t * label, label_candidate_t * candidate)
849 {
850     struct line_pnts *trsk;
851     double avedist = 0.0;
852     int i;
853 
854     G_debug(3, "Candidate point is: (%lf,%lf)",
855 	    candidate->point.x, candidate->point.y);
856     trsk = skyline_trans_rot(label->skyline, &candidate->point,
857 			     candidate->rotation);
858 
859     for (i = 0; i < trsk->n_points; i++) {
860 	double d;
861 
862 	Vect_line_distance(candidate->swathline, trsk->x[i], trsk->y[i],
863 			   0, 0, NULL, NULL, NULL, &d, NULL, NULL);
864 	avedist += d;
865     }
866 
867     for (i = 0; i < candidate->swathline->n_points; i++) {
868 	double d;
869 
870 	Vect_line_distance(trsk, candidate->swathline->x[i],
871 			   candidate->swathline->y[i], 0, 0,
872 			   NULL, NULL, NULL, &d, NULL, NULL);
873 	avedist += d;
874     }
875 
876     avedist /= (candidate->swathline->n_points + trsk->n_points);
877     Vect_destroy_line_struct(trsk);
878 
879     return ((avedist - ideal_distance) * (avedist - ideal_distance)) /
880 	(ideal_distance * ideal_distance);
881 }
882 
883 /**
884  * This function calculates the Flatness metric for line label candidates
885  * @param label The label to which candidate belongs to.
886  * @candidate The candidate of which we are to calculate the metric.
887  * @return The metric;
888  */
label_flatness(label_t * label,label_candidate_t * candidate)889 static double label_flatness(label_t * label, label_candidate_t * candidate)
890 {
891     struct line_pnts *line;
892     double flatness = 0.0, x0, y0, x1, y1, x2, y2;
893     int i;
894 
895     /* first generate a line which is parallel to the baseline,
896        but the ideal distance away from it, and is between the label and the
897        base line */
898     line = Vect_new_line_struct();
899     if (candidate->above) {
900 	x0 = x1 =
901 	    candidate->point.x + ideal_distance * sin(candidate->rotation);
902 	y0 = y1 =
903 	    candidate->point.y - ideal_distance * cos(candidate->rotation);
904     }
905     else {
906 	x0 = x1 =
907 	    candidate->point.x - ideal_distance * sin(candidate->rotation);
908 	y0 = y1 =
909 	    candidate->point.y + ideal_distance * cos(candidate->rotation);
910     }
911 
912     Vect_append_point(line, x1, y1, 0);
913     x2 = x1 + (label->bb.E - label->bb.W) * sin(candidate->rotation);
914     y2 = y1 + (label->bb.E - label->bb.W) * cos(candidate->rotation);
915     Vect_append_point(line, x2, y2, 0);
916 
917     /* now calculate the are between candidate->swathline and line */
918 
919     for (i = 1; i < candidate->swathline->n_points; i++) {
920 	int r;
921 	double b, h;
922 	double px1, py1, pz1, px2, py2, pz2;
923 
924 	r = Vect_segment_intersection(x1, y1, 0, x2, y2, 0,
925 				      candidate->swathline->x[i - 1],
926 				      candidate->swathline->y[i - 1],
927 				      0,
928 				      candidate->swathline->x[i],
929 				      candidate->swathline->y[i],
930 				      0,
931 				      &px1, &py1, &pz1, &px2, &py2, &pz2, 0);
932 	/* Now calculate the area between the swath and the line */
933 	switch (r) {
934 	case 0:		/* no intersection */
935 	    dig_distance2_point_to_line(candidate->swathline->x[i],
936 					candidate->swathline->y[i], 0,
937 					x1, y1, 0, x2, y2, 0, 0,
938 					&px1, &py1, &pz1, &h, NULL);
939 	    h = (sqrt(pow(x1 - candidate->swathline->x[i - 1], 2.0) +
940 		      pow(y1 - candidate->swathline->y[i - 1], 2.0)) +
941 		 h) / 2.0;
942 	    b = sqrt(pow(px1 - x1, 2) + pow(py1 - y1, 2));
943 	    flatness += b * h;
944 	    x1 = px1;
945 	    y1 = py1;
946 	    break;
947 	case 1:
948 	    h = sqrt(pow(x1 - candidate->swathline->x[i - 1], 2.0) +
949 		     pow(y1 - candidate->swathline->y[i - 1], 2.0));
950 	    b = sqrt(pow(px1 - x1, 2) + pow(py1 - y1, 2));
951 	    flatness += b * h * 0.5;	/* the first triangle */
952 	    x1 = px1;
953 	    y1 = py1;
954 	    dig_distance2_point_to_line(candidate->swathline->x[i],
955 					candidate->swathline->y[i], 0,
956 					x1, y1, 0, x2, y2, 0, 0,
957 					&px1, &py1, &pz1, &h, NULL);
958 	    b = sqrt(pow(px1 - x1, 2) + pow(py1 - y1, 2));
959 	    flatness += b * h * 0.5;	/* the second triangle */
960 	    x1 = px1;
961 	    y1 = py1;
962 	    break;
963 	case 3:
964 	    x1 = px2;
965 	    y1 = py2;
966 	    break;
967 	case 5:
968 	    x1 = px2;
969 	    y1 = py2;
970 	    break;
971 	default:
972 	    G_fatal_error("Programming error!!\n");
973 	    break;
974 	}
975     }
976 
977     flatness /= sqrt((x2 - x0) * (x2 - x0) + (y2 - y0) * (y2 - y0));	/* this is d'' */
978     flatness = (flatness * flatness) / (ideal_distance * ideal_distance);
979 
980     Vect_destroy_line_struct(line);
981     return flatness;
982 }
983 
984 /**
985  * This function checks if the label candidate overlaps with a point feature.
986  * And calculates the PointOver metric.
987  * @param label The label whose candidate we are investigating.
988  * @param candidate The label candidate we are investigating.
989  * @return The unweighted raw score of the PointOver metric for this label.
990  */
label_pointover(label_t * label,label_candidate_t * candidate)991 static double label_pointover(label_t * label, label_candidate_t * candidate)
992 {
993     double pointover;
994     struct ilist *il;
995     struct line_pnts *trbb;
996     int n;
997 
998     il = Vect_new_list();
999 
1000     /*    trsk = skyline_trans_rot(label->skyline, &candidate->point,
1001        candidate->rotation);
1002      */
1003     trbb = box_trans_rot(&label->bb, &candidate->point, candidate->rotation);
1004     n = Vect_select_lines_by_polygon(&Map, trbb, 0, NULL, GV_POINT, il);
1005 
1006     pointover = (double)il->n_values;
1007     Vect_destroy_list(il);
1008 
1009     return pointover;
1010 }
1011 
1012 /**
1013  * This function calculates the LineOver metric for a label candidate.
1014  * @param label The label whose candidate we are investigating.
1015  * @param candidate The label candidate we are investigating.
1016  * @return The unweighted raw score of the LineOver metric for this label.
1017  */
label_lineover(label_t * label,label_candidate_t * candidate,int linetype)1018 static double label_lineover(label_t * label, label_candidate_t * candidate,
1019 			     int linetype)
1020 {
1021     double lineover = 0.0;
1022     struct ilist *il;
1023     struct line_pnts *trbb;
1024     label_point_t b;
1025     int i, n;
1026 
1027     il = Vect_new_list();
1028     G_debug(5, "Candidate point is: (%lf,%lf)",
1029 	    candidate->point.x, candidate->point.y);
1030     /*    trsk = skyline_trans_rot(label->skyline, &candidate->point,
1031        candidate->rotation); */
1032     b.x = abs((label->bb.E - label->bb.W) * cos(candidate->rotation));
1033     b.y = abs((label->bb.E - label->bb.W) * sin(candidate->rotation));
1034 
1035     trbb = box_trans_rot(&label->bb, &candidate->point, candidate->rotation);
1036     n = Vect_select_lines_by_polygon(&Map, trbb, 0, NULL, linetype, il);
1037 
1038     if (n == 0) {
1039 	return 0.0;
1040     }
1041 
1042     for (i = 0; i < il->n_values; i++) {
1043 	int j, found = 0;
1044 	struct line_pnts *line;
1045 	label_point_t v, v1, v2;
1046 
1047 	line = Vect_new_line_struct();
1048 	Vect_read_line(&Map, line, NULL, il->value[i]);
1049 
1050 	for (j = 1; j < line->n_points; j++) {
1051 	    int k;
1052 
1053 	    for (k = 1; k < trbb->n_points; k++) {
1054 		int r;
1055 		double x1, x2, y1, y2, z1, z2;
1056 
1057 		r = Vect_segment_intersection(trbb->x[k - 1], trbb->y[k - 1],
1058 					      0, trbb->x[k], trbb->y[k], 0,
1059 					      line->x[j - 1], line->y[j - 1],
1060 					      0, line->x[j], line->y[j], 0,
1061 					      &x1, &y1, &z1, &x2, &y2, &z2,
1062 					      0);
1063 		if (r > 0) {	/* intersection at one point */
1064 		    if (found == 0) {
1065 			found = 1;
1066 			v1.x = x1;
1067 			v1.y = y1;
1068 		    }
1069 		    else {
1070 			found++;
1071 			if (r > 1) {
1072 			    v2.x = x2;
1073 			    v2.y = y2;
1074 			}
1075 			else {
1076 			    v2.x = x1;
1077 			    v2.y = y1;
1078 			}
1079 		    }
1080 		}
1081 	    }
1082 	}
1083 	if (found > 1) {
1084 	    double cosvb;
1085 
1086 	    v.x = abs(v2.x - v1.x);
1087 	    v.y = abs(v2.y - v1.y);
1088 	    cosvb = ((b.x * v.x + b.y * v.y) /
1089 		     (sqrt(b.x * b.x + b.y * b.y) *
1090 		      sqrt(v.x * v.x + v.y * v.y)));
1091 	    lineover += 1.0 + 9.0 * cosvb;
1092 	}
1093 	Vect_destroy_line_struct(line);
1094     }
1095 
1096     Vect_destroy_list(il);
1097     return lineover;
1098 }
1099 
1100 /**
1101  * This function calculates the minimum distance between a skyline and a swath line.
1102  * @param skyline The skyline to investigate.
1103  * @param swathline The swath line to investigate.
1104  * @param p The point on the skyline which is neares to the swath line is stored in this structure.
1105  * @return The distance in map units.
1106  */
min_dist_2_lines(struct line_pnts * skyline,struct line_pnts * swathline,label_point_t * p)1107 static double min_dist_2_lines(struct line_pnts *skyline,
1108 			       struct line_pnts *swathline, label_point_t * p)
1109 {
1110     int i;
1111     double dist = 10000000000000000.0;
1112 
1113     for (i = 0; i < skyline->n_points; i++) {
1114 	double x, y, d;
1115 
1116 	Vect_line_distance(swathline, skyline->x[i], skyline->y[i], 0, 0,
1117 			   &x, &y, NULL, &d, NULL, NULL);
1118 	if (d < dist) {
1119 	    dist = d;
1120 	    p->x = skyline->x[i];
1121 	    p->y = skyline->y[i];
1122 	}
1123     }
1124 
1125     for (i = 0; i < swathline->n_points; i++) {
1126 	double x, y, d;
1127 
1128 	Vect_line_distance(skyline, swathline->x[i], swathline->y[i], 0, 0,
1129 			   &x, &y, NULL, &d, NULL, NULL);
1130 	if (d < dist) {
1131 	    dist = d;
1132 	    p->x = x;
1133 	    p->y = y;
1134 	}
1135     }
1136 
1137     return dist;
1138 }
1139 
1140 /**
1141  * This function finds label -label overlaps.
1142  * @param labels The array of labels
1143  * @param n_labels The size of the array
1144  */
label_candidate_overlap(label_t * labels,int n_labels)1145 void label_candidate_overlap(label_t * labels, int n_labels)
1146 {
1147     int i;
1148 
1149     fprintf(stderr, "Finding label overlap: ...");
1150     for (i = 0; i < n_labels; i++) {
1151 	int j;
1152 
1153 	for (j = 0; j < labels[i].n_candidates; j++) {
1154 	    int k;
1155 
1156 	    for (k = i + 1; k < n_labels; k++) {
1157 		int l;
1158 
1159 		for (l = 0; l < labels[k].n_candidates; l++) {
1160 		    int overlap = 0;
1161 
1162 		    if ((labels[i].candidates[j].rotation == 0) &&
1163 			(labels[k].candidates[l].rotation == 0)) {
1164 			struct bound_box a, b;
1165 
1166 			a.N =
1167 			    labels[i].bb.N + labels[i].candidates[j].point.y;
1168 			a.E =
1169 			    labels[i].bb.E + labels[i].candidates[j].point.x;
1170 			a.W =
1171 			    labels[i].bb.W + labels[i].candidates[j].point.x;
1172 			a.S =
1173 			    labels[i].bb.S + labels[i].candidates[j].point.y;
1174 
1175 			b.N =
1176 			    labels[k].bb.N + labels[k].candidates[l].point.y;
1177 			b.E =
1178 			    labels[k].bb.E + labels[k].candidates[l].point.x;
1179 			b.W =
1180 			    labels[k].bb.W + labels[k].candidates[l].point.x;
1181 			b.S =
1182 			    labels[k].bb.S + labels[k].candidates[l].point.y;
1183 			overlap = box_overlap(&a, &b);
1184 		    }
1185 		    else {
1186 			struct line_pnts *a = NULL, *b = NULL;
1187 
1188 			a = box_trans_rot(&labels[i].bb,
1189 					  &labels[i].candidates[j].point,
1190 					  labels[i].candidates[j].rotation);
1191 			b = box_trans_rot(&labels[k].bb,
1192 					  &labels[k].candidates[l].point,
1193 					  labels[k].candidates[l].rotation);
1194 			overlap = box_overlap2(a, b);
1195 			Vect_destroy_line_struct(a);
1196 			Vect_destroy_line_struct(b);
1197 		    }
1198 		    if (overlap) {
1199 			int n;
1200 			label_intersection_t *li;
1201 
1202 			n = ++(labels[i].candidates[j].n_intersections);
1203 			li = G_realloc(labels[i].candidates[j].intersections,
1204 				     n * sizeof(label_intersection_t));
1205 			if (li == NULL)
1206 			    G_fatal_error("\nUnable to allocate memory\n");
1207 			li[n - 1].label = &labels[k];
1208 			li[n - 1].candidate = l;
1209 			if ((labels[k].current_candidate == l) &&
1210 			    (labels[i].current_candidate == j)) {
1211 			    labels[i].current_score += LABEL_OVERLAP_WEIGHT;
1212 			    labels[k].current_score += LABEL_OVERLAP_WEIGHT;
1213 			}
1214 			labels[i].candidates[j].intersections = li;
1215 			n = ++(labels[k].candidates[l].n_intersections);
1216 			li = G_realloc(labels[k].candidates[l].intersections,
1217 				     n * sizeof(label_intersection_t));
1218 			if (li == NULL)
1219 			    G_fatal_error("\nUnable to allocate memory\n");
1220 			li[n - 1].label = &labels[i];
1221 			li[n - 1].candidate = j;
1222 
1223 			labels[k].candidates[l].intersections = li;
1224 		    }
1225 		}
1226 	    }
1227 	}
1228 	G_percent(i, n_labels, 1);
1229     }
1230     G_percent(n_labels, n_labels, 1);
1231 }
1232 
1233 /**
1234  * This function checks if the two given boxes overlap.
1235  * @param a Bounding box A
1236  * @param b Bounding box B
1237  * @return REtruns 1 if the two boxes overlap 0 if not.
1238  */
box_overlap(struct bound_box * a,struct bound_box * b)1239 static int box_overlap(struct bound_box * a, struct bound_box * b)
1240 {
1241     int vert = 0, hori = 0;
1242 
1243     if (((a->W < b->W) && (b->W < a->E)) || ((a->W < b->E) && (b->E < a->E)))
1244 	vert = 1;
1245     if (((b->W < a->W) && (a->W < b->E)) || ((b->W < a->E) && (a->E < b->E)))
1246 	vert = 1;
1247 
1248     if (((a->S < b->S) && (b->S < a->N)) || ((a->S < b->N) && (b->N < a->N)))
1249 	hori = 1;
1250     if (((b->S < a->S) && (a->S < b->N)) || ((b->S < a->N) && (a->N < b->N)))
1251 	hori = 1;
1252 
1253     return (hori && vert);
1254 }
1255 
1256 /**
1257  * This function checks if two rotated boxes overlap. The boxes are stored
1258  * as polygons and the function assumes that each box has exactly 4 sides.
1259  * @param a Bounding box A
1260  * @param b Bounding box B
1261  * @return returns 1 if the given boxes overlap. 0 if not.
1262  */
box_overlap2(struct line_pnts * a,struct line_pnts * b)1263 static int box_overlap2(struct line_pnts *a, struct line_pnts *b)
1264 {
1265     int i, r = 0;
1266 
1267     for (i = 0; i < (a->n_points - 1); i++) {
1268 	int j;
1269 
1270 	for (j = 0; j < (b->n_points - 1); j++) {
1271 	    double d[6];
1272 
1273 	    r += Vect_segment_intersection(a->x[i], a->y[i], 0,
1274 					   a->x[i + 1], a->y[i + 1], 0,
1275 					   b->x[j], b->y[j], 0,
1276 					   b->x[j + 1], a->y[j + 1], 0,
1277 					   &d[0], &d[1], &d[2],
1278 					   &d[3], &d[4], &d[5], 0);
1279 	}
1280     }
1281     if (r > 1)
1282 	return 1;
1283     else
1284 	return 0;
1285 }
1286