Graphviz 12.0.1~dev.20240716.0800
Loading...
Searching...
No Matches
xlabels.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include <assert.h>
12#include <cgraph/alloc.h>
13#include <cgraph/exit.h>
14#include <errno.h>
15#include <limits.h>
16#include <math.h>
17#include <stdbool.h>
18#include <stdlib.h>
19#include <stdio.h>
20#include <string.h>
21#define XLABEL_INT
22#include <label/xlabels.h>
23
24static int icompare(void *, void *);
25
26Dtdisc_t Hdisc = { offsetof(HDict_t, key), sizeof(int), -1, 0, 0,
28};
29
30static int icompare(void *v1, void *v2) {
31 int k1 = *((int *) v1), k2 = *((int *) v2);
32 if (k1 < k2) {
33 return -1;
34 }
35 if (k1 > k2) {
36 return 1;
37 }
38 return 0;
39}
40
41static XLabels_t *xlnew(object_t *objs, size_t n_objs, xlabel_t *lbls,
42 size_t n_lbls, label_params_t *params) {
43 XLabels_t *xlp = gv_alloc(sizeof(XLabels_t));
44
45 /* used to load the rtree in hilbert space filling curve order */
46 if (!(xlp->hdx = dtopen(&Hdisc, Dtobag))) {
47 fprintf(stderr, "out of memory\n");
48 graphviz_exit(EXIT_FAILURE);
49 }
50
51 /* for querying intersection candidates */
52 if (!(xlp->spdx = RTreeOpen())) {
53 fprintf(stderr, "out of memory\n");
54 graphviz_exit(EXIT_FAILURE);
55 }
56 /* save arg pointers in the handle */
57 xlp->objs = objs;
58 xlp->n_objs = n_objs;
59 xlp->lbls = lbls;
60 xlp->n_lbls = n_lbls;
61 xlp->params = params;
62
63 return xlp;
64}
65
66static void xlfree(XLabels_t * xlp)
67{
68 RTreeClose(xlp->spdx);
69 free(xlp);
70}
71
72/***************************************************************************/
73
74/*
75 * determine the order(depth) of the hilbert sfc so that we satisfy the
76 * precondition of hd_hil_s_from_xy()
77 */
78static unsigned int xlhorder(XLabels_t * xlp)
79{
80 double maxx = xlp->params->bb.UR.x, maxy = xlp->params->bb.UR.y;
81 return (unsigned)floor(log2(round(fmax(maxx, maxy)))) + 1;
82}
83
84/* from http://www.hackersdelight.org/ site for the book by Henry S Warren */
85/*
86 * precondition
87 * pow(2, n) >= max(p.x, p.y)
88 */
89/* adapted from lams1.c
90Given the "order" n of a Hilbert curve and coordinates x and y, this
91program computes the length s of the curve from the origin to (x, y).
92The square that the Hilbert curve traverses is of size 2**n by 2**n.
93 The method is that given in [Lam&Shap], described by the following
94table. Here i = n-1 for the most significant bit of x and y, and i = 0
95for the least significant bits.
96
97 x[i] y[i] | s[2i+1:2i] x y
98 -----------|-------------------
99 0 0 | 00 y x
100 0 1 | 01 x y
101 1 0 | 11 ~y ~x
102 1 1 | 10 x y
103
104To use this table, start at the most significant bits of x and y
105(i = n - 1). If they are both 0 (first row), set the most significant
106two bits of s to 00 and interchange x and y. (Actually, it is only
107necessary to interchange the remaining bits of x and y.) If the most
108significant bits of x and y are 10 (third row), output 11, interchange x
109and y, and complement x and y.
110 Then, consider the next most significant bits of x and y (which may
111have been changed by this process), and select the appropriate row of
112the table to determine the next two bits of s, and how to change x and
113y. Continue until the least significant bits of x and y have been
114processed. */
115
116static unsigned int hd_hil_s_from_xy(point p, int n)
117{
118 int x = p.x, y = p.y;
119
120 unsigned s = 0; /* Initialize. */
121 for (int i = n - 1; i >= 0; i--) {
122 int xi = (x >> i) & 1; /* Get bit i of x. */
123 int yi = (y >> i) & 1; /* Get bit i of y. */
124 s = 4 * s + 2 * (unsigned)xi + ((unsigned)xi ^ (unsigned)yi); // Append two bits to s.
125
126 x = x ^ y; /* These 3 lines swap */
127 y = y ^ (x & (yi - 1)); /* x and y if yi = 0. */
128 x = x ^ y;
129 x = x ^ (-xi & (yi - 1)); /* Complement x and y if */
130 y = y ^ (-xi & (yi - 1)); /* xi = 1 and yi = 0. */
131 }
132 return s;
133}
134
135/* intersection test from
136 * from Real-Time Collision Detection 4.2.1 by Christer Ericson
137 * intersection area from
138 * http://stackoverflow.com/questions/4549544/total-area-of-intersecting-rectangles
139*/
140static double aabbaabb(Rect_t * r, Rect_t * s)
141{
142 if (!Overlap(r, s))
143 return 0;
144
145 /* if we get here we have an intersection */
146
147 /* rightmost left edge of the 2 rectangles */
148 double iminx =
149 r->boundary[0] > s->boundary[0] ? r->boundary[0] : s->boundary[0];
150 /* upmost bottom edge */
151 double iminy =
152 r->boundary[1] > s->boundary[1] ? r->boundary[1] : s->boundary[1];
153 /* leftmost right edge */
154 double imaxx =
155 r->boundary[2] < s->boundary[2] ? r->boundary[2] : s->boundary[2];
156 /* downmost top edge */
157 double imaxy =
158 r->boundary[3] < s->boundary[3] ? r->boundary[3] : s->boundary[3];
159 return (imaxx - iminx) * (imaxy - iminy);
160}
161
162/*
163 * test if objp1, a size 0 object is enclosed in the xlabel
164 * associated with objp
165 */
166static bool lblenclosing(object_t *objp, object_t *objp1) {
167 xlabel_t * xlp = objp->lbl;;
168
169 assert(objp1->sz.x == 0 && objp1->sz.y == 0);
170
171 if(! xlp) return false;
172
173 return objp1->pos.x > xlp->pos.x &&
174 objp1->pos.x < (xlp->pos.x + xlp->sz.x) &&
175 objp1->pos.y > xlp->pos.y &&
176 objp1->pos.y < (xlp->pos.y + xlp->sz.y);
177}
178
179/*fill in rectangle from the object */
180static Rect_t objp2rect(const object_t *op) {
181 Rect_t r = {0};
182 r.boundary[0] = op->pos.x;
183 r.boundary[1] = op->pos.y;
184 r.boundary[2] = op->pos.x + op->sz.x;
185 r.boundary[3] = op->pos.y + op->sz.y;
186 return r;
187}
188
189/*fill in rectangle from the objects xlabel */
190static Rect_t objplp2rect(const object_t *objp) {
191 Rect_t r = {0};
192 const xlabel_t *lp = objp->lbl;
193 r.boundary[0] = lp->pos.x;
194 r.boundary[1] = lp->pos.y;
195 r.boundary[2] = lp->pos.x + lp->sz.x;
196 r.boundary[3] = lp->pos.y + lp->sz.y;
197 return r;
198}
199
200/* compute boundary that encloses all possible label boundaries */
202{
203 Rect_t rect;
204 pointf p;
205
206 p.x = p.y = 0.0;
207 if (objp->lbl)
208 p = objp->lbl->sz;
209
210 rect.boundary[0] = (int) floor(objp->pos.x - p.x);
211 rect.boundary[1] = (int) floor(objp->pos.y - p.y);
212
213 rect.boundary[2] = (int) ceil(objp->pos.x + objp->sz.x + p.x);
214 assert(rect.boundary[2] < INT_MAX);
215 rect.boundary[3] = (int) ceil(objp->pos.y + objp->sz.y + p.y);
216 assert(rect.boundary[3] < INT_MAX);
217
218 return rect;
219}
220
221/* determine the position clp will occupy in intrsx[] */
222static int getintrsxi(object_t * op, object_t * cp)
223{
224 xlabel_t *lp = op->lbl, *clp = cp->lbl;
225 assert(lp != clp);
226
227 if (lp->set == 0 || clp->set == 0)
228 return -1;
229 if ((op->pos.x == 0.0 && op->pos.y == 0.0) ||
230 (cp->pos.x == 0.0 && cp->pos.y == 0.0))
231 return -1;
232
233 if (cp->pos.y < op->pos.y) {
234 if (cp->pos.x < op->pos.x)
235 return XLPXPY;
236 if (cp->pos.x > op->pos.x)
237 return XLNXPY;
238 return XLCXPY;
239 }
240 if (cp->pos.y > op->pos.y) {
241 if (cp->pos.x < op->pos.x)
242 return XLPXNY;
243 if (cp->pos.x > op->pos.x)
244 return XLNXNY;
245 return XLCXNY;
246 }
247 if (cp->pos.x < op->pos.x)
248 return XLPXCY;
249 if (cp->pos.x > op->pos.x)
250 return XLNXCY;
251
252 return -1;
253
254}
255
256/* record the intersecting objects label */
257static double
259 double a, object_t * intrsx[XLNBR])
260{
261 int i = getintrsxi(op, cp);
262 if (i < 0)
263 i = 5;
264 if (intrsx[i] != NULL) {
265 double sa, maxa = 0.0;
266 /* keep maximally overlapping object */
267 Rect_t srect = objp2rect(intrsx[i]);
268 sa = aabbaabb(rp, &srect);
269 if (sa > a)
270 maxa = sa;
271 /*keep maximally overlapping label */
272 if (intrsx[i]->lbl) {
273 srect = objplp2rect(intrsx[i]);
274 sa = aabbaabb(rp, &srect);
275 if (sa > a)
276 maxa = fmax(sa, maxa);
277 }
278 if (maxa > 0.0)
279 return maxa;
280 /*replace overlapping label/object pair */
281 intrsx[i] = cp;
282 return a;
283 }
284 intrsx[i] = cp;
285 return a;
286}
287
288/* record the intersecting label */
289static double
291 double a, object_t * intrsx[XLNBR])
292{
293 int i = getintrsxi(op, cp);
294 if (i < 0)
295 i = 5;
296 if (intrsx[i] != NULL) {
297 double sa, maxa = 0.0;
298 /* keep maximally overlapping object */
299 Rect_t srect = objp2rect(intrsx[i]);
300 sa = aabbaabb(rp, &srect);
301 if (sa > a)
302 maxa = sa;
303 /*keep maximally overlapping label */
304 if (intrsx[i]->lbl) {
305 srect = objplp2rect(intrsx[i]);
306 sa = aabbaabb(rp, &srect);
307 if (sa > a)
308 maxa = fmax(sa, maxa);
309 }
310 if (maxa > 0.0)
311 return maxa;
312 /*replace overlapping label/object pair */
313 intrsx[i] = cp;
314 return a;
315 }
316 intrsx[i] = cp;
317 return a;
318}
319
320/* find the objects and labels intersecting lp */
321static BestPos_t
322xlintersections(XLabels_t * xlp, object_t * objp, object_t * intrsx[XLNBR])
323{
324 BestPos_t bp;
325
326 assert(objp->lbl);
327
328 bp.n = 0;
329 bp.area = 0.0;
330 bp.pos = objp->lbl->pos;
331
332 for (size_t i = 0; i < xlp->n_objs; i++) {
333 if(objp == &xlp->objs[i]) continue;
334 if(xlp->objs[i].sz.x > 0 && xlp->objs[i].sz.y > 0) continue;
335 if(lblenclosing(objp, &xlp->objs[i]) ) {
336 bp.n++;
337 }
338 }
339
340 Rect_t rect = objplp2rect(objp);
341
342 LeafList_t *llp = RTreeSearch(xlp->spdx, xlp->spdx->root, &rect);
343 if (!llp)
344 return bp;
345
346 for (LeafList_t *ilp = llp; ilp; ilp = ilp->next) {
347 double a, ra;
348 object_t *cp = ilp->leaf->data;
349
350 if (cp == objp)
351 continue;
352
353 /*label-object intersect */
354 Rect_t srect = objp2rect(cp);
355 a = aabbaabb(&rect, &srect);
356 if (a > 0.0) {
357 ra = recordointrsx(objp, cp, &rect, a, intrsx);
358 bp.n++;
359 bp.area += ra;
360 }
361 /*label-label intersect */
362 if (!cp->lbl || !cp->lbl->set)
363 continue;
364 srect = objplp2rect(cp);
365 a = aabbaabb(&rect, &srect);
366 if (a > 0.0) {
367 ra = recordlintrsx(objp, cp, &rect, a, intrsx);
368 bp.n++;
369 bp.area += ra;
370 }
371 }
373 return bp;
374}
375
376/*
377 * xladjust - find a label position
378 * the individual tests at the top are intended to place a preference order
379 * on the position
380 */
381static BestPos_t xladjust(XLabels_t * xlp, object_t * objp)
382{
383 xlabel_t *lp = objp->lbl;
384 double xincr = (2 * lp->sz.x + objp->sz.x) / XLXDENOM;
385 double yincr = (2 * lp->sz.y + objp->sz.y) / XLYDENOM;
386 object_t *intrsx[XLNBR] = {0};
387 BestPos_t bp, nbp;
388
389 assert(objp->lbl);
390
391 /*x left */
392 lp->pos.x = objp->pos.x - lp->sz.x;
393 /*top */
394 lp->pos.y = objp->pos.y + objp->sz.y;
395 bp = xlintersections(xlp, objp, intrsx);
396 if (bp.n == 0)
397 return bp;
398 /*mid */
399 lp->pos.y = objp->pos.y;
400 nbp = xlintersections(xlp, objp, intrsx);
401 if (nbp.n == 0)
402 return nbp;
403 if (nbp.area < bp.area)
404 bp = nbp;
405 /*bottom */
406 lp->pos.y = objp->pos.y - lp->sz.y;
407 nbp = xlintersections(xlp, objp, intrsx);
408 if (nbp.n == 0)
409 return nbp;
410 if (nbp.area < bp.area)
411 bp = nbp;
412
413 /*x mid */
414 lp->pos.x = objp->pos.x;
415 /*top */
416 lp->pos.y = objp->pos.y + objp->sz.y;
417 nbp = xlintersections(xlp, objp, intrsx);
418 if (nbp.n == 0)
419 return nbp;
420 if (nbp.area < bp.area)
421 bp = nbp;
422 /*bottom */
423 lp->pos.y = objp->pos.y - lp->sz.y;
424 nbp = xlintersections(xlp, objp, intrsx);
425 if (nbp.n == 0)
426 return nbp;
427 if (nbp.area < bp.area)
428 bp = nbp;
429
430 /*x right */
431 lp->pos.x = objp->pos.x + objp->sz.x;
432 /*top */
433 lp->pos.y = objp->pos.y + objp->sz.y;
434 nbp = xlintersections(xlp, objp, intrsx);
435 if (nbp.n == 0)
436 return nbp;
437 if (nbp.area < bp.area)
438 bp = nbp;
439 /*mid */
440 lp->pos.y = objp->pos.y;
441 nbp = xlintersections(xlp, objp, intrsx);
442 if (nbp.n == 0)
443 return nbp;
444 if (nbp.area < bp.area)
445 bp = nbp;
446 /*bottom */
447 lp->pos.y = objp->pos.y - lp->sz.y;
448 nbp = xlintersections(xlp, objp, intrsx);
449 if (nbp.n == 0)
450 return nbp;
451 if (nbp.area < bp.area)
452 bp = nbp;
453
454 /*sliding from top left */
455 if (intrsx[XLPXNY] || intrsx[XLCXNY] || intrsx[XLNXNY] || intrsx[XLPXCY] || intrsx[XLPXPY]) { /* have to move */
456 if (!intrsx[XLCXNY] && !intrsx[XLNXNY]) { /* some room right? */
457 /* slide along upper edge */
458 for (lp->pos.x = objp->pos.x - lp->sz.x,
459 lp->pos.y = objp->pos.y + objp->sz.y;
460 lp->pos.x <= (objp->pos.x + objp->sz.x);
461 lp->pos.x += xincr) {
462 nbp = xlintersections(xlp, objp, intrsx);
463 if (nbp.n == 0)
464 return nbp;
465 if (nbp.area < bp.area)
466 bp = nbp;
467 }
468 }
469 if (!intrsx[XLPXCY] && !intrsx[XLPXPY]) { /* some room down? */
470 /* slide down left edge */
471 for (lp->pos.x = objp->pos.x - lp->sz.x,
472 lp->pos.y = objp->pos.y + objp->sz.y;
473 lp->pos.y >= (objp->pos.y - lp->sz.y);
474 lp->pos.y -= yincr) {
475 nbp = xlintersections(xlp, objp, intrsx);
476 if (nbp.n == 0)
477 return nbp;
478 if (nbp.area < bp.area)
479 bp = nbp;
480
481 }
482 }
483 }
484
485 /*sliding from bottom right */
486 lp->pos.x = objp->pos.x + objp->sz.x;
487 lp->pos.y = objp->pos.y - lp->sz.y;
488 if (intrsx[XLNXPY] || intrsx[XLCXPY] || intrsx[XLPXPY] || intrsx[XLNXCY] || intrsx[XLNXNY]) { /* have to move */
489 if (!intrsx[XLCXPY] && !intrsx[XLPXPY]) { /* some room left? */
490 /* slide along lower edge */
491 for (lp->pos.x = objp->pos.x + objp->sz.x,
492 lp->pos.y = objp->pos.y - lp->sz.y;
493 lp->pos.x >= (objp->pos.x - lp->sz.x);
494 lp->pos.x -= xincr) {
495 nbp = xlintersections(xlp, objp, intrsx);
496 if (nbp.n == 0)
497 return nbp;
498 if (nbp.area < bp.area)
499 bp = nbp;
500 }
501 }
502 if (!intrsx[XLNXCY] && !intrsx[XLNXNY]) { /* some room up? */
503 /* slide up right edge */
504 for (lp->pos.x = objp->pos.x + objp->sz.x,
505 lp->pos.y = objp->pos.y - lp->sz.y;
506 lp->pos.y <= (objp->pos.y + objp->sz.y);
507 lp->pos.y += yincr) {
508 nbp = xlintersections(xlp, objp, intrsx);
509 if (nbp.n == 0)
510 return nbp;
511 if (nbp.area < bp.area)
512 bp = nbp;
513 }
514 }
515 }
516 return bp;
517}
518
519/* load the hilbert sfc keyed tree */
520static int xlhdxload(XLabels_t * xlp)
521{
522 int order = xlhorder(xlp);
523
524 for (size_t i = 0; i < xlp->n_objs; i++) {
525 HDict_t *hp;
526 point pi;
527
528 hp = gv_alloc(sizeof(HDict_t));
529
530 hp->d.data = &xlp->objs[i];
531 hp->d.rect = objplpmks(&xlp->objs[i]);
532 /* center of the labeling area */
533 pi.x = hp->d.rect.boundary[0] +
534 (hp->d.rect.boundary[2] - hp->d.rect.boundary[0]) / 2;
535 pi.y = hp->d.rect.boundary[1] +
536 (hp->d.rect.boundary[3] - hp->d.rect.boundary[1]) / 2;
537
538 hp->key = hd_hil_s_from_xy(pi, order);
539
540 if (!dtinsert(xlp->hdx, hp))
541 return -1;
542 }
543 return 0;
544}
545
546static void xlhdxunload(XLabels_t * xlp)
547{
548 int size=dtsize(xlp->hdx), freed=0;
549 while(dtsize(xlp->hdx) ) {
550 void*vp=dtfinger(xlp->hdx);
551 assert(vp);
552 if(vp) {
553 dtdetach(xlp->hdx, vp);
554 free(vp);
555 freed++;
556 }
557 }
558 assert(size==freed);
559 (void)size;
560}
561
562static void xlspdxload(XLabels_t *xlp) {
563 for (HDict_t *op = dtfirst(xlp->hdx); op; op = dtnext(xlp->hdx, op)) {
564 /* tree rectangle data node lvl */
565 RTreeInsert(xlp->spdx, &op->d.rect, op->d.data, &xlp->spdx->root, 0);
566 }
567}
568
569static int xlinitialize(XLabels_t * xlp)
570{
571 int r=0;
572 if ((r = xlhdxload(xlp)) < 0)
573 return r;
574 xlspdxload(xlp);
575 xlhdxunload(xlp);
576 return dtclose(xlp->hdx);
577}
578
579int placeLabels(object_t *objs, size_t n_objs, xlabel_t *lbls, size_t n_lbls,
580 label_params_t *params) {
581 int r;
582 BestPos_t bp;
583 XLabels_t *xlp = xlnew(objs, n_objs, lbls, n_lbls, params);
584 if ((r = xlinitialize(xlp)) < 0)
585 return r;
586
587 /* Place xlabel_t* lp near lp->obj so that the rectangle whose lower-left
588 * corner is lp->pos, and size is lp->sz does not intersect any object
589 * in objs (by convention, an object consisting of a single point
590 * intersects nothing) nor any other label, if possible. On input,
591 * lp->set is 0.
592 *
593 * On output, any label with a position should have this stored in
594 * lp->pos and have lp->set non-zero.
595 *
596 * If params->force is true, all labels must be positioned, even if
597 * overlaps are necessary.
598 *
599 * Return 0 if all labels could be placed without overlap;
600 * non-zero otherwise.
601 */
602 r = 0;
603 for (size_t i = 0; i < n_objs; i++) {
604 if (objs[i].lbl == 0)
605 continue;
606 bp = xladjust(xlp, &objs[i]);
607 if (bp.n == 0) {
608 objs[i].lbl->set = 1;
609 } else if(bp.area == 0) {
610 objs[i].lbl->pos.x = bp.pos.x;
611 objs[i].lbl->pos.y = bp.pos.y;
612 objs[i].lbl->set = 1;
613 } else if (params->force == 1) {
614 objs[i].lbl->pos.x = bp.pos.x;
615 objs[i].lbl->pos.y = bp.pos.y;
616 objs[i].lbl->set = 1;
617 } else {
618 r = 1;
619 }
620 }
621 xlfree(xlp);
622 return r;
623}
Memory allocation wrappers that exit on failure.
static void * gv_alloc(size_t size)
Definition alloc.h:47
CDT_API Dtmethod_t * Dtobag
ordered multiset
Definition dttree.c:305
#define dtdetach(d, o)
Definition cdt.h:195
CDT_API int dtsize(Dt_t *)
Definition dtsize.c:12
#define dtfinger(d)
Definition cdt.h:185
#define dtinsert(d, o)
Definition cdt.h:193
CDT_API int dtclose(Dt_t *)
Definition dtclose.c:8
CDT_API Dt_t * dtopen(Dtdisc_t *, Dtmethod_t *)
Definition dtopen.c:9
#define dtnext(d, o)
Definition cdt.h:188
#define dtfirst(d)
Definition cdt.h:187
static NORETURN void graphviz_exit(int status)
Definition exit.h:23
disc key
Definition exparse.y:214
void free(void *)
node NULL
Definition grammar.y:149
htmllabel_t * lbl
Definition htmlparse.c:93
LeafList_t * RTreeSearch(RTree_t *rtp, Node_t *n, Rect_t *r)
Definition index.c:140
void RTreeLeafListFree(LeafList_t *llp)
Definition index.c:40
RTree_t * RTreeOpen(void)
Definition index.c:51
int RTreeClose(RTree_t *rtp)
Definition index.c:89
int RTreeInsert(RTree_t *rtp, Rect_t *r, void *data, Node_t **n, int level)
Definition index.c:182
bool Overlap(const Rect_t *r, const Rect_t *s)
Definition rectangle.c:108
struct LeafList * next
Definition index.h:61
int boundary[NUMSIDES]
Definition rectangle.h:21
unsigned char force
Definition xlabels.h:36
xlabel_t * lbl
Definition xlabels.h:31
pointf pos
Definition xlabels.h:29
pointf sz
Definition xlabels.h:30
Definition geom.h:27
int y
Definition geom.h:27
int x
Definition geom.h:27
double x
Definition geom.h:29
double y
Definition geom.h:29
unsigned char set
Definition xlabels.h:25
pointf sz
Definition xlabels.h:22
pointf pos
Definition xlabels.h:23
Definition grammar.c:93
static BestPos_t xlintersections(XLabels_t *xlp, object_t *objp, object_t *intrsx[XLNBR])
Definition xlabels.c:322
Dtdisc_t Hdisc
Definition xlabels.c:26
static double recordlintrsx(object_t *op, object_t *cp, Rect_t *rp, double a, object_t *intrsx[XLNBR])
Definition xlabels.c:290
int placeLabels(object_t *objs, size_t n_objs, xlabel_t *lbls, size_t n_lbls, label_params_t *params)
Definition xlabels.c:579
static void xlfree(XLabels_t *xlp)
Definition xlabels.c:66
static void xlspdxload(XLabels_t *xlp)
Definition xlabels.c:562
static Rect_t objplp2rect(const object_t *objp)
Definition xlabels.c:190
static double aabbaabb(Rect_t *r, Rect_t *s)
Definition xlabels.c:140
static Rect_t objp2rect(const object_t *op)
Definition xlabels.c:180
static void xlhdxunload(XLabels_t *xlp)
Definition xlabels.c:546
static int getintrsxi(object_t *op, object_t *cp)
Definition xlabels.c:222
static bool lblenclosing(object_t *objp, object_t *objp1)
Definition xlabels.c:166
static int xlinitialize(XLabels_t *xlp)
Definition xlabels.c:569
static XLabels_t * xlnew(object_t *objs, size_t n_objs, xlabel_t *lbls, size_t n_lbls, label_params_t *params)
Definition xlabels.c:41
static BestPos_t xladjust(XLabels_t *xlp, object_t *objp)
Definition xlabels.c:381
static double recordointrsx(object_t *op, object_t *cp, Rect_t *rp, double a, object_t *intrsx[XLNBR])
Definition xlabels.c:258
static Rect_t objplpmks(object_t *objp)
Definition xlabels.c:201
static unsigned int hd_hil_s_from_xy(point p, int n)
Definition xlabels.c:116
static unsigned int xlhorder(XLabels_t *xlp)
Definition xlabels.c:78
static int icompare(void *, void *)
Definition xlabels.c:30
static int xlhdxload(XLabels_t *xlp)
Definition xlabels.c:520