lib/neatogen/Makefile
lib/fdpgen/Makefile
lib/sparse/Makefile
+ lib/label/Makefile
lib/sfdpgen/Makefile
lib/osage/Makefile
lib/gvpr/Makefile
SUBDIRS = cdt graph cgraph gd pathplan sfio vmalloc ast \
vpsc rbtree ortho sparse patchwork expr common \
- pack xdot gvc ingraphs topfish glcomp \
+ pack xdot gvc ingraphs topfish glcomp label \
circogen dotgen dotgen2 fdpgen neatogen twopigen sfdpgen osage gvpr
EXTRA_DIST = Makefile.old gvc.vcproj gvc.def
-I$(top_srcdir) \
-I$(top_srcdir)/lib/gvc \
-I$(top_srcdir)/lib/pack \
+ -I$(top_srcdir)/lib/label \
-I$(top_srcdir)/lib/xdot \
-I$(top_srcdir)/lib/fdpgen \
-I$(top_srcdir)/lib/pathplan \
emit_begin_node(job, n);
ND_shape(n)->fns->codefn(job, n);
- if (ND_xlabel(n))
+ if (ND_xlabel(n) && ND_xlabel(n)->set)
emit_label(job, EMIT_NLABEL, ND_xlabel(n));
emit_end_node(job);
}
return TRUE;
lp = ED_xlabel(e);
- if (lp && overlap_label(lp, b))
+ if (lp && lp->set && overlap_label(lp, b))
return TRUE;
return FALSE;
char* newid;
char* type;
- if (lbl == NULL) return;
+ if ((lbl == NULL) || !(lbl->set)) return;
if (id) { /* non-NULL if needed */
newid = N_NEW(strlen(id) + sizeof("-headlabel"),char);
switch (lkind) {
EXTERN int MaxIter;
EXTERN int Ndim;
EXTERN int State; /* last finished phase */
+ EXTERN int EdgeLabelsDone; /* true if edge labels have been positioned */
EXTERN double Initial_dist;
EXTERN double Damping;
EXTERN int Y_invert; /* invert y in dot & plain output */
p = agget(g, "concentrate");
Concentrate = mapbool(p);
State = GVBEGIN;
+ EdgeLabelsDone = 0;
GD_drawing(g)->dpi = 0.0;
if (((p = agget(g, "dpi")) && p[0])
sprintf(buf, "%.5g", PS2INCH(ND_lw(n) + ND_rw(n)));
agxset(n, N_width, buf);
#endif
- if (ND_xlabel(n)) {
+ if (ND_xlabel(n) && ND_xlabel(n)->set) {
ptf = ND_xlabel(n)->pos;
sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y));
agset(n, "xlp", buf);
sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y));
agset(e, "lp", buf);
}
- if (ED_xlabel(e)) {
+ if (ED_xlabel(e) && ED_xlabel(e)->set) {
ptf = ED_xlabel(e)->pos;
sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y));
agset(e, "xlp", buf);
#include "render.h"
+#include "xlabels.h"
static int Rankdir;
static boolean Flip;
static pointf map_point(pointf p)
{
- p = ccwrotatepf(p, Rankdir*90);
+ p = ccwrotatepf(p, Rankdir * 90);
p.x -= Offset.x;
p.y -= Offset.y;
return p;
if (ED_spl(e) == NULL) {
if ((Concentrate == FALSE) || (ED_edge_type(e) != IGNORED))
- agerr(AGERR, "lost %s %s edge\n",agnameof(agtail(e)),
+ agerr(AGERR, "lost %s %s edge\n", agnameof(agtail(e)),
agnameof(aghead(e)));
return;
}
edge_t *e;
int shift = (Offset.x || Offset.y);
- if (!shift && !Rankdir) return;
+ if (!shift && !Rankdir)
+ return;
for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
- if (Rankdir) gv_nodesize(v, FALSE);
+ if (Rankdir)
+ gv_nodesize(v, FALSE);
ND_coord(v) = map_point(ND_coord(v));
if (ND_xlabel(v))
ND_xlabel(v)->pos = map_point(ND_xlabel(v)->pos);
GD_label(g)->set = TRUE;
}
-static void
-addXLabels (Agraph_t* g)
+static pointf
+centerPt (xlabel_t* xlp) {
+ pointf p;
+
+ p = xlp->pos;
+ p.x += (xlp->sz.x)/2.0;
+ p.y += (xlp->sz.y)/2.0;
+
+ return p;
+}
+
+static int
+printData (object_t* objs, int n_objs, xlabel_t* lbls, int n_lbls,
+ label_params_t* params) {
+ int i;
+ fprintf (stderr, "%d objs %d xlabels force=%d bb=(%.02f,%.02f) (%.02f,%.02f)\n",
+ n_objs, n_lbls, params->force, params->bb.LL.x, params->bb.LL.y,
+ params->bb.UR.x, params->bb.UR.y);
+ if (Verbose < 2) return 0;
+ for (i = 0; i < n_objs; i++) {
+ fprintf (stderr, " [%d] (%.02f,%.02f) (%.02f,%.02f) %p\n",
+ i, objs->pos.x,objs->pos.y,objs->sz.x,objs->sz.y, objs->lbl);
+ objs++;
+ }
+ for (i = 0; i < n_lbls; i++) {
+ fprintf (stderr, " [%d] %p (%.02f,%.02f) %s\n",
+ i, lbls, lbls->sz.x,lbls->sz.y, ((textlabel_t*)lbls->lbl)->text);
+ lbls++;
+ }
+ return 0;
+}
+
+/* addXLabels:
+ * Position xlabels and any unpositioned edge labels using
+ * a map placement algorithm to avoid overlap.
+ *
+ * TODO: interaction with spline=ortho
+ * interaction with rankdir=LR
+ */
+static void addXLabels(Agraph_t * gp)
{
+ Agnode_t *np;
+ Agedge_t *ep;
+ int cnt, i, n_objs, n_lbls;
+ int n_nlbls = 0; /* # of node xlabels */
+ int n_elbls = 0; /* # of edge xlabels */
+ int n_set_elbls = 0; /* # of edge labels set */
+ boxf bb;
+ pointf ur;
textlabel_t* lp;
- pointf p, pp;
- Agnode_t* n;
-
- for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
- lp = ND_xlabel(n);
- if (!lp) continue;
- p = ND_coord(n);
-
- pp.y = p.y;
- pp.x += p.x + ND_rw(n) + lp->dimen.x/2.0;
- lp->pos = pp;
- lp->set = 1;
+ label_params_t params;
+ object_t* objs;
+ xlabel_t* lbls;
+ object_t* objp;
+ xlabel_t* xlp;
+ Agsym_t* force;
+
+ if (!(GD_has_labels(gp) & NODE_XLABEL) &&
+ !(GD_has_labels(gp) & EDGE_XLABEL) &&
+ ((!GD_has_labels(gp) & EDGE_LABEL) || EdgeLabelsDone))
+ return;
+
+ for (np = agfstnode(gp); np; np = agnxtnode(gp, np)) {
+ if (ND_xlabel(np))
+ n_nlbls++;
+ for (ep = agfstout(gp, np); ep; ep = agnxtout(gp, ep)) {
+ if (ED_xlabel(ep))
+ n_elbls++;
+ if (ED_label(ep)) {
+ if (ED_label(ep)->set)
+ n_set_elbls++;
+ else
+ n_elbls++;
+ }
+ }
+ }
+
+ /* An object for each node, each positioned edge label, and all unset edge
+ * labels and xlabels.
+ */
+ n_objs = agnnodes(gp) + n_set_elbls + n_elbls;
+ /* A label for each unpositioned label */
+ n_lbls = n_nlbls + n_elbls;
+ objp = objs = N_NEW(n_objs, object_t);
+ xlp = lbls = N_NEW(n_lbls, xlabel_t);
+ bb.LL = pointfof(INT_MAX, INT_MAX);
+ bb.UR = pointfof(-INT_MAX, -INT_MAX);
+
+ for (np = agfstnode(gp); np; np = agnxtnode(gp, np)) {
+ /* Add an obstacle per node */
+ objp->sz.x = INCH2PS(ND_width(np));
+ objp->sz.y = INCH2PS(ND_height(np));
+ objp->pos = ND_coord(np);
+ objp->pos.x -= (objp->sz.x) / 2.0;
+ objp->pos.y -= (objp->sz.y) / 2.0;
+
+ /* Adjust bounding box */
+ bb.LL.x = MIN(bb.LL.x, objp->pos.x);
+ bb.LL.y = MIN(bb.LL.y, objp->pos.y);
+ ur.x = objp->pos.x + objp->sz.x;
+ ur.y = objp->pos.y + objp->sz.y;
+ bb.UR.x = MAX(bb.UR.x, ur.x);
+ bb.UR.y = MAX(bb.UR.y, ur.y);
+
+ if (ND_xlabel(np)) {
+ xlp->sz = ND_xlabel(np)->dimen;
+ xlp->lbl = ND_xlabel(np);
+ xlp->set = 0;
+ objp->lbl = xlp;
+ xlp++;
+ }
+ objp++;
+ for (ep = agfstout(gp, np); ep; ep = agnxtout(gp, ep)) {
+ if ((lp = ED_label(ep))) {
+ if (lp->set) {
+ objp->sz.x = lp->dimen.x;
+ objp->sz.y = lp->dimen.y;
+ objp->pos = lp->pos;
+ objp->pos.x -= (objp->sz.x) / 2.0;
+ objp->pos.y -= (objp->sz.y) / 2.0;
+
+ /* Adjust bounding box */
+ bb.LL.x = MIN(bb.LL.x, objp->pos.x);
+ bb.LL.y = MIN(bb.LL.y, objp->pos.y);
+ ur.x = objp->pos.x + objp->sz.x;
+ ur.y = objp->pos.y + objp->sz.y;
+ bb.UR.x = MAX(bb.UR.x, ur.x);
+ bb.UR.y = MAX(bb.UR.y, ur.y);
+ }
+ else {
+ objp->sz.x = 0;
+ objp->sz.y = 0;
+ objp->pos = edgeMidpoint(gp, ep);
+
+ xlp->sz = ED_label(ep)->dimen;
+ xlp->lbl = ED_label(ep);
+ xlp->set = 0;
+ objp->lbl = xlp;
+ xlp++;
+ }
+ objp++;
+ }
+ if (ED_xlabel(ep)) {
+ objp->sz.x = 0;
+ objp->sz.y = 0;
+ objp->pos = edgeMidpoint(gp, ep);
+
+ xlp->sz = ED_xlabel(ep)->dimen;
+ xlp->lbl = ED_xlabel(ep);
+ xlp->set = 0;
+ objp->lbl = xlp;
+ xlp++;
+ objp++;
+ }
+ }
+ }
+
+ force = agfindgraphattr(gp, "forcelabels");
+
+ params.force = late_bool(gp, force, FALSE);
+ params.bb = bb;
+ if (Verbose)
+ printData(objs, n_objs, lbls, n_lbls, ¶ms);
+ placeLabels(objs, n_objs, lbls, n_lbls, ¶ms);
+
+ xlp = lbls;
+ cnt = 0;
+ for (i = 0; i < n_lbls; i++) {
+ if (xlp->set) {
+ cnt++;
+ lp = (textlabel_t *) (xlp->lbl);
+ lp->set = 1;
+ lp->pos = centerPt(xlp);
+ updateBB (gp, lp);
+ }
+ xlp++;
}
+ if (Verbose)
+ fprintf (stderr, "%d out of %d labels positioned.\n", cnt, n_lbls);
+ free(objs);
+ free(lbls);
}
/* dotneato_postprocess:
* Assumes the boxes of all clusters have been computed.
* When done, the bounding box of g has LL at origin.
*/
-void gv_postprocess(Agraph_t *g, int allowTranslation)
+void gv_postprocess(Agraph_t * g, int allowTranslation)
{
double diff;
- pointf dimen = {0., 0.};
+ pointf dimen = { 0., 0. };
- addXLabels (g);
+ addXLabels(g);
Rankdir = GD_rankdir(g);
Flip = GD_flip(g);
else
place_graph_label(g);
- /* Add space for graph label if necessary */
+ /* Add space for graph label if necessary */
if (GD_label(g) && !GD_label(g)->set) {
dimen = GD_label(g)->dimen;
PAD(dimen);
if (Flip)
sprintf(buf, M2, Offset.x, Offset.y, Offset.x, Offset.y);
else
- sprintf(buf, M1, Offset.y, Offset.x, Offset.y, Offset.x,
- -Offset.x, -Offset.y);
+ sprintf(buf, M1, Offset.y, Offset.x, Offset.y, Offset.x,
+ -Offset.x, -Offset.y);
Show_boxes[0] = strdup(buf);
}
}
void dotneato_postprocess(Agraph_t * g)
{
- gv_postprocess (g, 1);
+ gv_postprocess(g, 1);
}
/* place_flip_graph_label:
#ifndef WITH_CGRAPH
if ((g != g->root) && (GD_label(g)) && !GD_label(g)->set) {
-#else /* WITH_CGRAPH */
+#else /* WITH_CGRAPH */
if ((g != agroot(g)) && (GD_label(g)) && !GD_label(g)->set) {
-#endif /* WITH_CGRAPH */
+#endif /* WITH_CGRAPH */
if (GD_label_pos(g) & LABEL_AT_TOP) {
d = GD_border(g)[RIGHT_IX];
#ifndef WITH_CGRAPH
if ((g != g->root) && (GD_label(g)) && !GD_label(g)->set) {
-#else /* WITH_CGRAPH */
+#else /* WITH_CGRAPH */
if ((g != agroot(g)) && (GD_label(g)) && !GD_label(g)->set) {
-#endif /* WITH_CGRAPH */
+#endif /* WITH_CGRAPH */
if (GD_label_pos(g) & LABEL_AT_TOP) {
d = GD_border(g)[TOP_IX];
p.y = GD_bb(g).UR.y - d.y / 2;
*/
void addEdgeLabels(graph_t* g, edge_t * e, pointf rp, pointf rq)
{
+#if 0
int et = EDGE_TYPE (g);
pointf p, q;
pointf d; /* midpoint of segment p-q */
ED_label(e)->set = TRUE;
updateBB(agraphof(agtail(e)), ED_label(e));
}
+#endif
makePortLabels(e);
}
}
#endif
State = GVSPLINES;
+ EdgeLabelsDone = 1;
}
/* dot_splines:
libgvc_C_la_LIBADD = \
$(top_builddir)/lib/pack/libpack_C.la \
$(top_builddir)/lib/xdot/libxdot_C.la \
+ $(top_builddir)/lib/label/liblabel_C.la \
$(top_builddir)/lib/common/libcommon_C.la
libgvc_C_la_DEPENDENCIES = \
$(top_builddir)/lib/pack/libpack_C.la \
$(top_builddir)/lib/xdot/libxdot_C.la \
+ $(top_builddir)/lib/label/liblabel_C.la \
$(top_builddir)/lib/common/libcommon_C.la
if WITH_ORTHO
libgvc_C_la_LIBADD += $(top_builddir)/lib/ortho/libortho_C.la
--- /dev/null
+# $Id$ $Revision$
+## Process this file with automake to produce Makefile.in
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/lib/gvc \
+ -I$(top_srcdir)/lib/pathplan \
+ -I$(top_srcdir)/lib/common \
+ -I$(top_srcdir)/lib/graph \
+ -I$(top_srcdir)/lib/cdt
+
+noinst_HEADERS = xlabels.h index.h node.h rectangle.h split.q.h
+noinst_LTLIBRARIES = liblabel_C.la
+
+liblabel_C_la_SOURCES = xlabels.c index.c node.c rectangle.c split.q.c
+
+EXTRA_DIST = rtmain.c
+
--- /dev/null
+/* vim:set shiftwidth=4 ts=8: */
+
+/*************************************************************************
+ * Copyright (c) 2011 AT&T Intellectual Property
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors: See CVS logs. Details at http://www.graphviz.org/
+ *************************************************************************/
+
+#include <stdlib.h>
+
+#include "index.h"
+#include <stdio.h>
+#include <assert.h>
+#include "logic.h"
+#include "memory.h"
+
+LeafList_t *RTreeNewLeafList(Leaf_t * lp)
+{
+ LeafList_t *llp;
+
+ if ((llp = NEW(LeafList_t)))
+ llp->leaf = lp;
+ return llp;
+}
+
+LeafList_t *RTreeLeafListAdd(LeafList_t * llp, Leaf_t * lp)
+{
+ LeafList_t *nlp;
+ if (!lp)
+ return llp;
+
+ nlp = RTreeNewLeafList(lp);
+ nlp->next = llp;
+ return nlp;
+}
+
+void RTreeLeafListFree(LeafList_t * llp)
+{
+ LeafList_t *tlp;
+ while (llp->next) {
+ tlp = llp->next;
+ free(llp);
+ llp = tlp;
+ }
+ return;
+}
+
+/* Allocate space for a node in the list used in DeletRect to
+ * store Nodes that are too empty.
+ */
+static struct ListNode *RTreeNewListNode()
+{
+ return NEW(struct ListNode);
+}
+
+#if UNUSED
+static void RTreeFreeListNode(struct ListNode *p)
+{
+ free(p);
+}
+#endif
+
+/* Add a node to the reinsertion list. All its branches will later
+ * be reinserted into the index structure.
+ */
+static int RTreeReInsert(RTree_t * rtp, Node_t * n, struct ListNode **ee)
+{
+ register struct ListNode *l;
+
+ if (!(l = RTreeNewListNode()))
+ return -1;
+ l->node = n;
+ l->next = *ee;
+ *ee = l;
+ return 0;
+}
+
+RTree_t *RTreeOpen()
+{
+ RTree_t *rtp;
+
+ if ((rtp = NEW(RTree_t)))
+ rtp->root = RTreeNewIndex(rtp);
+ return rtp;
+}
+
+/* Make a new index, empty. Consists of a single node. */
+Node_t *RTreeNewIndex(RTree_t * rtp)
+{
+ Node_t *x;
+ x = RTreeNewNode(rtp);
+ x->level = 0; /* leaf */
+ rtp->LeafCount++;
+ return x;
+}
+
+static int RTreeClose2(RTree_t * rtp, Node_t * n)
+{
+ int i;
+
+ if (n->level > 0) {
+ for (i = 0; i < NODECARD; i++) {
+ if (!n->branch[i].child)
+ continue;
+ if (!RTreeClose2(rtp, n->branch[i].child)) {
+ free(n->branch[i].child);
+ DisconBranch(n, i);
+ rtp->EntryCount--;
+ if (rtp->StatFlag)
+ rtp->ElimCount++;
+ }
+ }
+ } else {
+ for (i = 0; i < NODECARD; i++) {
+ if (!n->branch[i].child)
+ continue;
+ DisconBranch(n, i);
+ rtp->EntryCount--;
+ }
+ }
+ return 0;
+}
+
+
+int RTreeClose(RTree_t * rtp)
+{
+ RTreeClose2(rtp, rtp->root);
+ free(rtp);
+ return 0;
+}
+
+#ifdef RTDEBUG
+/* Print out all the nodes in an index.
+** Prints from root downward.
+*/
+void PrintIndex(Node_t * n)
+{
+ int i;
+ Node_t *nn;
+ assert(n);
+ assert(n->level >= 0);
+
+ if (n->level > 0) {
+ for (i = 0; i < NODECARD; i++) {
+ if ((nn = n->branch[i].child) != NULL)
+ PrintIndex(nn);
+ }
+ }
+
+ PrintNode(n);
+}
+
+/* Print out all the data rectangles in an index.
+*/
+void PrintData(Node_t * n)
+{
+ int i;
+ Node_t *nn;
+ assert(n);
+ assert(n->level >= 0);
+
+ if (n->level == 0)
+ PrintNode(n);
+ else {
+ for (i = 0; i < NODECARD; i++) {
+ if ((nn = n->branch[i].child) != NULL)
+ PrintData(nn);
+ }
+ }
+}
+#endif
+
+/* RTreeSearch in an index tree or subtree for all data retangles that
+** overlap the argument rectangle.
+** Returns the number of qualifying data rects.
+*/
+LeafList_t *RTreeSearch(RTree_t * rtp, Node_t * n, Rect_t * r)
+{
+ register int i;
+ LeafList_t *llp = 0;
+
+ assert(n);
+ assert(n->level >= 0);
+ assert(r);
+
+ rtp->SeTouchCount++;
+
+ if (n->level > 0) { /* this is an internal node in the tree */
+ for (i = 0; i < NODECARD; i++)
+ if (n->branch[i].child && Overlap(r, &n->branch[i].rect)) {
+ LeafList_t *tlp = RTreeSearch(rtp, n->branch[i].child, r);
+ if (llp) {
+ LeafList_t *xlp = llp;
+ while (xlp->next)
+ xlp = xlp->next;
+ xlp->next = tlp;
+ } else
+ llp = tlp;
+ }
+ } else { /* this is a leaf node */
+ for (i = 0; i < NODECARD; i++) {
+ if (n->branch[i].child && Overlap(r, &n->branch[i].rect)) {
+ llp = RTreeLeafListAdd(llp, (Leaf_t *) & n->branch[i]);
+# ifdef RTDEBUG
+ PrintRect(&n->branch[i].rect);
+# endif
+ }
+ }
+ }
+ return llp;
+}
+
+/* Insert a data rectangle into an index structure.
+** RTreeInsert provides for splitting the root;
+** returns 1 if root was split, 0 if it was not.
+** The level argument specifies the number of steps up from the leaf
+** level to insert; e.g. a data rectangle goes in at level = 0.
+** RTreeInsert2 does the recursion.
+*/
+static int RTreeInsert2(RTree_t *, Rect_t *, void *, Node_t *, Node_t **,
+ int);
+/*static int RTreeInsert2(RTree_t*, Rect_t*, int, Node_t*, Node_t**, int); */
+
+int
+RTreeInsert(RTree_t * rtp, Rect_t * r, void *data, Node_t ** n, int level)
+{
+ /* RTreeInsert(RTree_t*rtp, Rect_t*r, int data, Node_t**n, int level) { */
+ register int i;
+ register Node_t *newroot;
+ Node_t *newnode;
+ Branch_t b;
+ int result = 0;
+
+
+ assert(r && n);
+ assert(level >= 0 && level <= (*n)->level);
+ for (i = 0; i < NUMDIMS; i++)
+ assert(r->boundary[i] <= r->boundary[NUMDIMS + i]);
+
+# ifdef RTDEBUG
+ fprintf(stderr, "RTreeInsert level=%d\n", level);
+# endif
+
+ if (rtp->StatFlag) {
+ if (rtp->Deleting)
+ rtp->ReInsertCount++;
+ else
+ rtp->InsertCount++;
+ }
+ if (!rtp->Deleting)
+ rtp->RectCount++;
+
+ if (RTreeInsert2(rtp, r, data, *n, &newnode, level)) { /* root was split */
+ if (rtp->StatFlag) {
+ if (rtp->Deleting)
+ rtp->DeTouchCount++;
+ else
+ rtp->InTouchCount++;
+ }
+
+ newroot = RTreeNewNode(rtp); /* grow a new root, make tree taller */
+ rtp->NonLeafCount++;
+ newroot->level = (*n)->level + 1;
+ b.rect = NodeCover(*n);
+ b.child = *n;
+ AddBranch(rtp, &b, newroot, NULL);
+ b.rect = NodeCover(newnode);
+ b.child = newnode;
+ AddBranch(rtp, &b, newroot, NULL);
+ *n = newroot;
+ rtp->EntryCount += 2;
+ result = 1;
+ }
+
+ return result;
+}
+
+/* Inserts a new data rectangle into the index structure.
+** Recursively descends tree, propagates splits back up.
+** Returns 0 if node was not split. Old node updated.
+** If node was split, returns 1 and sets the pointer pointed to by
+** new to point to the new node. Old node updated to become one of two.
+** The level argument specifies the number of steps up from the leaf
+** level to insert; e.g. a data rectangle goes in at level = 0.
+*/
+static int
+RTreeInsert2(RTree_t * rtp, Rect_t * r, void *data,
+ Node_t * n, Node_t ** new, int level)
+{
+ /*static int */
+ /* RTreeInsert2(RTree_t*rtp, Rect_t*r,
+ int data, Node_t*n, Node_t**new, int level) {
+ */
+ register int i;
+ Branch_t b;
+ Node_t *n2;
+
+ assert(r && n && new);
+ assert(level >= 0 && level <= n->level);
+
+ if (rtp->StatFlag) {
+ if (rtp->Deleting)
+ rtp->DeTouchCount++;
+ else
+ rtp->InTouchCount++;
+ }
+
+ /* Still above level for insertion, go down tree recursively */
+ if (n->level > level) {
+ i = PickBranch(r, n);
+ if (!RTreeInsert2(rtp, r, data, n->branch[i].child, &n2, level)) { /* recurse: child was not split */
+ n->branch[i].rect = CombineRect(r, &(n->branch[i].rect));
+ return 0;
+ } else { /* child was split */
+ n->branch[i].rect = NodeCover(n->branch[i].child);
+ b.child = n2;
+ b.rect = NodeCover(n2);
+ rtp->EntryCount++;
+ return AddBranch(rtp, &b, n, new);
+ }
+ } else if (n->level == level) { /* at level for insertion. */
+ /*Add rect, split if necessary */
+ b.rect = *r;
+ b.child = (Node_t *) data;
+ rtp->EntryCount++;
+ return AddBranch(rtp, &b, n, new);
+ } else { /* Not supposed to happen */
+ assert(FALSE);
+ return 0;
+ }
+}
+
+static void FreeListNode(register struct ListNode *p)
+{
+ free(p);
+}
+
+/* Delete a data rectangle from an index structure.
+** Pass in a pointer to a Rect, the data of the record, ptr to ptr to root node.
+** Returns 1 if record not found, 0 if success.
+** RTreeDelete provides for eliminating the root.
+*/
+static int RTreeDelete2(RTree_t *, Rect_t *, void *, Node_t *,
+ ListNode_t **);
+/* static int RTreeDelete2(RTree_t*, Rect_t*, int, Node_t*, ListNode_t**); */
+
+int RTreeDelete(RTree_t * rtp, Rect_t * r, void *data, Node_t ** nn)
+{
+ /* int */
+ /* RTreeDelete(RTree_t*rtp, Rect_t*r, int data, Node_t**nn) { */
+ register int i;
+ register Node_t *t;
+ struct ListNode *reInsertList = NULL;
+ register struct ListNode *e;
+
+ assert(r && nn);
+ assert(*nn);
+ assert(data >= 0);
+
+ rtp->Deleting = TRUE;
+
+# ifdef RTDEBUG
+ fprintf(stderr, "RTreeDelete\n");
+# endif
+
+ if (!RTreeDelete2(rtp, r, data, *nn, &reInsertList)) {
+ /* found and deleted a data item */
+ if (rtp->StatFlag)
+ rtp->DeleteCount++;
+ rtp->RectCount--;
+
+ /* reinsert any branches from eliminated nodes */
+ while (reInsertList) {
+ t = reInsertList->node;
+ for (i = 0; i < NODECARD; i++) {
+ if (t->branch[i].child) {
+ RTreeInsert(rtp, &(t->branch[i].rect),
+ /* (int)t->branch[i].child, nn, t->level); */
+ t->branch[i].child, nn, t->level);
+ rtp->EntryCount--;
+ }
+ }
+ e = reInsertList;
+ reInsertList = reInsertList->next;
+ RTreeFreeNode(rtp, e->node);
+ FreeListNode(e);
+ }
+
+ /* check for redundant root (not leaf, 1 child) and eliminate */
+ if ((*nn)->count == 1 && (*nn)->level > 0) {
+ if (rtp->StatFlag)
+ rtp->ElimCount++;
+ rtp->EntryCount--;
+ for (i = 0; i < NODECARD; i++) {
+ if ((t = (*nn)->branch[i].child))
+ break;
+ }
+ RTreeFreeNode(rtp, *nn);
+ *nn = t;
+ }
+ rtp->Deleting = FALSE;
+ return 0;
+ } else {
+ rtp->Deleting = FALSE;
+ return 1;
+ }
+}
+
+/* Delete a rectangle from non-root part of an index structure.
+** Called by RTreeDelete. Descends tree recursively,
+** merges branches on the way back up.
+*/
+static int
+RTreeDelete2(RTree_t * rtp, Rect_t * r, void *data, Node_t * n,
+ ListNode_t ** ee)
+/* static int */
+/* RTreeDelete2(RTree_t*rtp, Rect_t*r, int data, Node_t*n, ListNode_t**ee) */
+{
+ register int i;
+ Rect_t NodeCover();
+
+ assert(r && n && ee);
+ assert(data >= 0);
+ assert(n->level >= 0);
+
+ if (rtp->StatFlag)
+ rtp->DeTouchCount++;
+
+ if (n->level > 0) { /* not a leaf node */
+ for (i = 0; i < NODECARD; i++) {
+ if (n->branch[i].child && Overlap(r, &(n->branch[i].rect))) {
+ if (!RTreeDelete2(rtp, r, data, n->branch[i].child, ee)) { /*recurse */
+ if (n->branch[i].child->count >= rtp->MinFill)
+ n->branch[i].rect = NodeCover(n->branch[i].child);
+ else { /* not enough entries in child, eliminate child node */
+ RTreeReInsert(rtp, n->branch[i].child, ee);
+ DisconBranch(n, i);
+ rtp->EntryCount--;
+ if (rtp->StatFlag)
+ rtp->ElimCount++;
+ }
+ return 0;
+ }
+ }
+ }
+ return 1;
+ } else { /* a leaf node */
+ for (i = 0; i < NODECARD; i++) {
+ if (n->branch[i].child
+ && n->branch[i].child == (Node_t *) data) {
+ DisconBranch(n, i);
+ rtp->EntryCount--;
+ return 0;
+ }
+ }
+ return 1;
+ }
+}
+
+#ifdef UNUSED
+/* Allocate space for a node in the list used in DeletRect to
+** store Nodes that are too empty.
+*/
+struct ListNode *NewListNode()
+{
+ return (struct ListNode *) malloc(sizeof(struct ListNode));
+}
+
+#endif
--- /dev/null
+/* vim:set shiftwidth=4 ts=8: */
+
+/*************************************************************************
+ * Copyright (c) 2011 AT&T Intellectual Property
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors: See CVS logs. Details at http://www.graphviz.org/
+ *************************************************************************/
+
+#ifndef INDEX_H
+#define INDEX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * this library is derived from an archived home directory of Antonin Guttman
+ * that implemented the ideas described in
+ * "R-trees: a dynamic index structure for spatial searching"
+ * Antonin Guttman, University of California, Berkeley
+ * SIGMOD '84 Proceedings of the 1984 ACM SIGMOD international conference on Management of data
+ * ISBN:0-89791-128-8
+ * http://dx.doi.org/10.1145/602259.602266
+ * this copy of the code was retrieved from
+ * http://web.archive.org/web/20030210112132/http://www.es.ucsc.edu/~tonig/rtrees/
+ * we are using the quadratic node splitter only
+ * we made a few cosmetic changes to fit our needs
+ * per Antonin there is no copyright
+ */
+
+/* %W% %G% */
+/*-----------------------------------------------------------------------------
+| Global definitions.
+-----------------------------------------------------------------------------*/
+
+#ifndef NUMDIMS
+#define NUMDIMS 2
+#endif /*NUMDIMS*/
+/* #define NDEBUG */
+#define NUMSIDES 2*NUMDIMS
+/* branching factor of a node */
+/* #define NODECARD (int)((PGSIZE-(2*sizeof(int)))/sizeof(struct Branch))*/
+#define NODECARD 64
+typedef struct RTree RTree_t;
+
+#include <rectangle.h>
+#include <node.h>
+#include <split.q.h>
+
+#define CX(i) (i)
+#define NX(i) (i+NUMDIMS)
+#define CY(i) (i+1)
+#define NY(i) (i+1+NUMDIMS)
+
+typedef struct Leaf {
+ Rect_t rect;
+ void *data;
+} Leaf_t;
+
+typedef struct LeafList {
+ struct LeafList *next;
+ Leaf_t *leaf;
+} LeafList_t;
+
+#ifndef METHODS
+#define METHODS 1
+#endif /*METHODS*/
+ struct RTree {
+ Node_t *root;
+
+ SplitQ_t split;
+
+ /* balance criterion for node splitting */
+ int MinFill;
+
+ /* times */
+ long ElapsedTime;
+ float UserTime, SystemTime;
+
+ int Deleting;
+
+ /* variables for statistics */
+ int StatFlag; /* tells if we are counting or not */
+ /* counters affected only when StatFlag set */
+ int InsertCount;
+ int DeleteCount;
+ int ReInsertCount;
+ int InSplitCount;
+ int DeSplitCount;
+ int ElimCount;
+ int EvalCount;
+ int InTouchCount;
+ int DeTouchCount;
+ int SeTouchCount;
+ int CallCount;
+ float SplitMeritSum;
+
+ /* counters used even when StatFlag not set */
+ int RectCount;
+ int NodeCount;
+ int LeafCount, NonLeafCount;
+ int EntryCount;
+ int SearchCount;
+ int HitCount;
+
+};
+
+typedef struct ListNode {
+ struct ListNode *next;
+ struct Node *node;
+} ListNode_t;
+
+RTree_t *RTreeOpen();
+int RTreeClose(RTree_t * rtp);
+Node_t *RTreeNewIndex(RTree_t * rtp);
+LeafList_t *RTreeSearch(RTree_t *, Node_t *, Rect_t *);
+int RTreeInsert(RTree_t *, Rect_t *, void *, Node_t **, int);
+int RTreeDelete(RTree_t *, Rect_t *, void *, Node_t **);
+
+LeafList_t *RTreeNewLeafList(Leaf_t * lp);
+LeafList_t *RTreeLeafListAdd(LeafList_t * llp, Leaf_t * lp);
+void RTreeLeafListFree(LeafList_t * llp);
+
+#ifdef RTDEBUG
+void PrintNode(Node_t *);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*INDEX_H */
--- /dev/null
+/* vim:set shiftwidth=4 ts=8: */
+
+/*************************************************************************
+ * Copyright (c) 2011 AT&T Intellectual Property
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors: See CVS logs. Details at http://www.graphviz.org/
+ *************************************************************************/
+
+#include <stdlib.h>
+
+#include "index.h"
+#include <stdio.h>
+#include <assert.h>
+#include "node.h"
+
+/* Make a new node and initialize to have all branch cells empty.
+*/
+Node_t *RTreeNewNode(RTree_t * rtp)
+{
+ register Node_t *n;
+
+ rtp->NodeCount++;
+ n = (Node_t *) malloc(sizeof(Node_t));
+ InitNode(n);
+ return n;
+}
+
+void RTreeFreeNode(RTree_t * rtp, Node_t * p)
+{
+ rtp->NodeCount--;
+ if (p->level == 0)
+ rtp->LeafCount--;
+ else
+ rtp->NonLeafCount--;
+ free(p);
+}
+
+/* Initialize a Node structure.
+*/
+void InitNode(Node_t * n)
+{
+ register int i;
+ n->count = 0;
+ n->level = -1;
+ for (i = 0; i < NODECARD; i++)
+ InitBranch(&(n->branch[i]));
+}
+
+/* Initialize one branch cell in a node.
+*/
+void InitBranch(Branch_t * b)
+{
+ InitRect(&(b->rect));
+ b->child = NULL;
+}
+
+#ifdef RTDEBUG
+/* Print out the data in a node.
+*/
+void PrintNode(Node_t * n)
+{
+ int i;
+ assert(n);
+
+ fprintf(stderr, "node");
+ if (n->level == 0)
+ fprintf(stderr, " LEAF");
+ else if (n->level > 0)
+ fprintf(stderr, " NONLEAF");
+ else
+ fprintf(stderr, " TYPE=?");
+ fprintf(stderr, " level=%d count=%d child address=%X\n",
+ n->level, n->count, (unsigned int) n);
+
+ for (i = 0; i < NODECARD; i++) {
+ if (n->branch[i].child != NULL)
+ PrintBranch(i, &n->branch[i]);
+ }
+}
+
+void PrintBranch(int i, Branch_t * b)
+{
+ fprintf(stderr, " child[%d] X%X\n", i, (unsigned int) b->child);
+ PrintRect(&(b->rect));
+}
+#endif
+
+/* Find the smallest rectangle that includes all rectangles in
+** branches of a node.
+*/
+Rect_t NodeCover(Node_t * n)
+{
+ register int i, flag;
+ Rect_t r, CombineRect();
+ assert(n);
+
+ InitRect(&r);
+ flag = 1;
+ for (i = 0; i < NODECARD; i++)
+ if (n->branch[i].child) {
+ if (flag) {
+ r = n->branch[i].rect;
+ flag = 0;
+ } else
+ r = CombineRect(&r, &(n->branch[i].rect));
+ }
+ return r;
+}
+
+/* Pick a branch. Pick the one that will need the smallest increase
+** in area to accomodate the new rectangle. This will result in the
+** least total area for the covering rectangles in the current node.
+** In case of a tie, pick the one which was smaller before, to get
+** the best resolution when searching.
+*/
+int PickBranch(Rect_t * r, Node_t * n)
+{
+ register Rect_t *rr;
+ register int i, flag, increase, bestIncr, area, bestArea;
+ int best;
+ Rect_t CombineRect();
+ assert(r && n);
+
+ flag = 1;
+ for (i = 0; i < NODECARD; i++) {
+ if (n->branch[i].child) {
+ Rect_t rect;
+ rr = &n->branch[i].rect;
+ area = RectArea(rr);
+ /* increase = RectArea(&CombineRect(r, rr)) - area; */
+ rect = CombineRect(r, rr);
+ increase = RectArea(&rect) - area;
+ if (increase < bestIncr || flag) {
+ best = i;
+ bestArea = area;
+ bestIncr = increase;
+ flag = 0;
+ } else if (increase == bestIncr && area < bestArea) {
+ best = i;
+ bestArea = area;
+ bestIncr = increase;
+ }
+# ifdef RTDEBUG
+ fprintf(stderr,
+ "i=%d area before=%d area after=%d increase=%d\n",
+ i, area, area + increase, increase);
+# endif
+ }
+ }
+# ifdef RTDEBUG
+ fprintf(stderr, "\tpicked %d\n", best);
+# endif
+ return best;
+}
+
+/* Add a branch to a node. Split the node if necessary.
+** Returns 0 if node not split. Old node updated.
+** Returns 1 if node split, sets *new to address of new node.
+** Old node updated, becomes one of two.
+*/
+int AddBranch(RTree_t * rtp, Branch_t * b, Node_t * n, Node_t ** new)
+{
+ register int i;
+
+ assert(b);
+ assert(n);
+
+ if (n->count < NODECARD) { /* split won't be necessary */
+ for (i = 0; i < NODECARD; i++) { /* find empty branch */
+ if (n->branch[i].child == NULL) {
+ n->branch[i] = *b;
+ n->count++;
+ break;
+ }
+ }
+ assert(i < NODECARD);
+ return 0;
+ } else {
+ if (rtp->StatFlag) {
+ if (rtp->Deleting)
+ rtp->DeTouchCount++;
+ else
+ rtp->InTouchCount++;
+ }
+ assert(new);
+ SplitNode(rtp, n, b, new);
+ if (n->level == 0)
+ rtp->LeafCount++;
+ else
+ rtp->NonLeafCount++;
+ return 1;
+ }
+}
+
+/* Disconnect a dependent node.
+*/
+void DisconBranch(Node_t * n, int i)
+{
+ assert(n && i >= 0 && i < NODECARD);
+ assert(n->branch[i].child);
+
+ InitBranch(&(n->branch[i]));
+ n->count--;
+}
--- /dev/null
+/* vim:set shiftwidth=4 ts=8: */
+
+/*************************************************************************
+ * Copyright (c) 2011 AT&T Intellectual Property
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors: See CVS logs. Details at http://www.graphviz.org/
+ *************************************************************************/
+
+#ifndef NODE_H
+#define NODE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <index.h>
+
+typedef struct Branch {
+ Rect_t rect;
+ struct Node *child;
+} Branch_t;
+
+typedef struct Node {
+ int count;
+ int level; /* 0 is leaf, others positive */
+ struct Branch branch[NODECARD];
+} Node_t;
+
+void RTreeFreeNode(RTree_t *, Node_t *);
+void InitNode(Node_t *);
+void InitBranch(Branch_t *);
+Rect_t NodeCover(Node_t *);
+int PickBranch(Rect_t *, Node_t *);
+int AddBranch(RTree_t *, Branch_t *, Node_t *, Node_t **);
+void DisconBranch(Node_t *, int);
+void PrintBranch(int, Branch_t *);
+Node_t *RTreeNewNode(RTree_t *);
+#ifdef RTDEBUG
+void PrintNode(Node_t * n);
+void PrintBranch(int i, Branch_t * b);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*NODE_H */
--- /dev/null
+/* vim:set shiftwidth=4 ts=8: */
+
+/*************************************************************************
+ * Copyright (c) 2011 AT&T Intellectual Property
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors: See CVS logs. Details at http://www.graphviz.org/
+ *************************************************************************/
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <memory.h>
+#include <gvc.h>
+#include "xlabels.h"
+
+#if 0
+#define POINTS_PER_INCH 72
+#define N_NEW(n,t) (t*)calloc((n),sizeof(t))
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#define INT_MAX ((int)(~(unsigned)0 >> 1))
+#define INCH2PS(a_inches) ((a_inches)*(double)POINTS_PER_INCH)
+#endif
+
+static char *progname;
+static int Verbose;
+extern pointf edgeMidpoint(graph_t * g, edge_t * e);
+
+static inline pointf pointfof(double x, double y)
+{
+ pointf r;
+
+ r.x = x;
+ r.y = y;
+ return r;
+}
+
+typedef struct {
+ GVC_t *gvc;
+ char *infname;
+ char *outfname;
+ FILE *inf;
+ FILE *outf;
+ char *lay;
+ char *fmt;
+ int force;
+} opts_t;
+
+static pointf centerPt(xlabel_t * xlp)
+{
+ pointf p;
+
+ p = xlp->pos;
+ p.x += (xlp->sz.x) / 2.0;
+ p.y += (xlp->sz.y) / 2.0;
+
+ return p;
+}
+
+static int
+printData(object_t * objs, int n_objs, xlabel_t * lbls, int n_lbls,
+ label_params_t * params)
+{
+ int i;
+ fprintf(stderr,
+ "%d objs %d xlabels force=%d bb=(%.02f,%.02f) (%.02f,%.02f)\n",
+ n_objs, n_lbls, params->force, params->bb.LL.x,
+ params->bb.LL.y, params->bb.UR.x, params->bb.UR.y);
+ if (Verbose < 2)
+ return 0;
+ for (i = 0; i < n_objs; i++) {
+ fprintf(stderr, " [%d] (%.02f,%.02f) (%.02f,%.02f) %p\n",
+ i, objs->pos.x, objs->pos.y, objs->sz.x, objs->sz.y,
+ objs->lbl);
+ objs++;
+ }
+ for (i = 0; i < n_lbls; i++) {
+ fprintf(stderr, " [%d] %p (%.02f,%.02f) %s\n",
+ i, lbls, lbls->sz.x, lbls->sz.y,
+ ((textlabel_t *) lbls->lbl)->text);
+ lbls++;
+ }
+ return 0;
+}
+
+int doxlabel(opts_t * opts)
+{
+ Agraph_t *gp;
+ object_t *objs;
+ xlabel_t *lbls;
+ int i, n_objs, n_lbls;
+ label_params_t params;
+ Agnode_t *np;
+ Agedge_t *ep;
+ int n_nlbls = 0, n_elbls = 0;
+ boxf bb;
+ textlabel_t *lp;
+ object_t *objp;
+ xlabel_t *xlp;
+ pointf ur;
+
+ fprintf(stderr, "reading %s\n", opts->infname);
+ if (!(gp = agread(opts->inf))) {
+ fprintf(stderr, "%s: %s not a dot file\n", progname,
+ opts->infname);
+ exit(1);
+ }
+ fclose(opts->inf);
+
+ fprintf(stderr, "laying out %s\n", opts->lay);
+ if (gvLayout(opts->gvc, gp, opts->lay)) {
+ fprintf(stderr, "%s: layout %s failed\n", progname, opts->lay);
+ exit(1);
+ }
+
+ fprintf(stderr, "attach labels\n");
+ /* In the real code, this should be optimized using GD_has_labels() */
+ /* We could probably provide the number of node and edge xlabels */
+ for (np = agfstnode(gp); np; np = agnxtnode(gp, np)) {
+ if (ND_xlabel(np))
+ n_nlbls++;
+ for (ep = agfstout(gp, np); ep; ep = agnxtout(gp, ep)) {
+ if (ED_xlabel(ep))
+ n_elbls++;
+ }
+ }
+ n_objs = agnnodes(gp) + n_elbls;
+ n_lbls = n_nlbls + n_elbls;
+ objp = objs = N_NEW(n_objs, object_t);
+ xlp = lbls = N_NEW(n_lbls, xlabel_t);
+ bb.LL = pointfof(INT_MAX, INT_MAX);
+ bb.UR = pointfof(-INT_MAX, -INT_MAX);
+
+ for (np = agfstnode(gp); np; np = agnxtnode(gp, np)) {
+ /* Add an obstacle per node */
+ objp->sz.x = INCH2PS(ND_width(np));
+ objp->sz.y = INCH2PS(ND_height(np));
+ objp->pos = ND_coord(np);
+ objp->pos.x -= (objp->sz.x) / 2.0;
+ objp->pos.y -= (objp->sz.y) / 2.0;
+
+ /* Adjust bounding box */
+ bb.LL.x = MIN(bb.LL.x, objp->pos.x);
+ bb.LL.y = MIN(bb.LL.y, objp->pos.y);
+ ur.x = objp->pos.x + objp->sz.x;
+ ur.y = objp->pos.y + objp->sz.y;
+ bb.UR.x = MAX(bb.UR.x, ur.x);
+ bb.UR.y = MAX(bb.UR.y, ur.y);
+
+ if (ND_xlabel(np)) {
+ xlp->sz = ND_xlabel(np)->dimen;
+ xlp->lbl = ND_xlabel(np);
+ xlp->set = 0;
+ objp->lbl = xlp;
+ xlp++;
+ }
+ objp++;
+ for (ep = agfstout(gp, np); ep; ep = agnxtout(gp, ep)) {
+ if (ED_label(ep)) {
+ textlabel_t *lp = ED_label(ep);
+ lp->pos.x = lp->pos.y = 0.0;
+ }
+ if (!ED_xlabel(ep))
+ continue;
+ objp->sz.x = 0;
+ objp->sz.y = 0;
+ objp->pos = edgeMidpoint(gp, ep);
+
+ xlp->sz = ED_xlabel(ep)->dimen;
+ xlp->lbl = ED_xlabel(ep);
+ xlp->set = 0;
+ objp->lbl = xlp;
+ xlp++;
+ objp++;
+ }
+ }
+
+ params.force = opts->force;
+ params.bb = bb;
+ if (Verbose)
+ printData(objs, n_objs, lbls, n_lbls, ¶ms);
+ placeLabels(objs, n_objs, lbls, n_lbls, ¶ms);
+
+ fprintf(stderr, "read label positions\n");
+ xlp = lbls;
+ for (i = 0; i < n_lbls; i++) {
+ if (xlp->set) {
+ lp = (textlabel_t *) (xlp->lbl);
+ lp->set = 1;
+ lp->pos = centerPt(xlp);
+ }
+ xlp++;
+ }
+ free(objs);
+ free(lbls);
+
+ fprintf(stderr, "writing %s\n", opts->outfname);
+ gvRender(opts->gvc, gp, opts->fmt, opts->outf);
+
+ /* clean up */
+ fprintf(stderr, "cleaning up\n");
+ gvFreeLayout(opts->gvc, gp);
+ agclose(gp);
+ return 0;
+}
+
+int checkOpt(char *l, char *legal[], int n)
+{
+ int i;
+ for (i = 0; i < n; i++) {
+ if (strcmp(l, legal[i]) == 0)
+ return 1;
+ }
+ return 0;
+}
+
+void usage(char *pp)
+{
+ fprintf(stderr,
+ "Usage: %s [-fv] [-V$level] [-T$fmt] [-l$layout] [-o$outfile] dotfile\n",
+ pp);
+ return;
+}
+
+static FILE *openFile(char *name, char *mode)
+{
+ FILE *fp;
+ char *modestr;
+
+ fp = fopen(name, mode);
+ if (!fp) {
+ if (*mode == 'r')
+ modestr = "reading";
+ else
+ modestr = "writing";
+ fprintf(stderr, "%s: could not open file %s for %s -- %s\n",
+ progname, name, modestr, strerror(errno));
+ exit(1);
+ }
+ return (fp);
+}
+
+static void init(int argc, char *argv[], opts_t * opts)
+{
+ int c, cnt;
+ char **optList;
+ opts->outf = stdout;
+ opts->outfname = "stdout";
+
+ progname = argv[0];
+ opts->gvc = gvContext();
+ opts->lay = "dot";
+ opts->fmt = "ps";
+ opts->force = 0;
+
+ while ((c = getopt(argc, argv, "o:vFl:T:V:")) != EOF) {
+ switch (c) {
+ case 'F':
+ opts->force = 1;
+ break;
+ case 'l':
+ optList = gvPluginList(opts->gvc, "layout", &cnt, NULL);
+ if (checkOpt(optarg, optList, cnt))
+ opts->lay = optarg;
+ else {
+ fprintf(stderr, "%s: unknown layout %s\n", progname,
+ optarg);
+ exit(1);
+ }
+ break;
+ case 'T':
+ optList = gvPluginList(opts->gvc, "device", &cnt, NULL);
+ if (checkOpt(optarg, optList, cnt))
+ opts->fmt = optarg;
+ else {
+ fprintf(stderr, "%s: unknown format %s\n", progname,
+ optarg);
+ exit(1);
+ }
+ break;
+ case 'v':
+ Verbose = 1;
+ break;
+ case 'V':
+ Verbose = atoi(optarg);
+ break;
+ case 'o':
+ opts->outf = openFile(optarg, "w");
+ opts->outfname = optarg;
+ break;
+ default:
+ usage(progname);
+ exit(1);
+ }
+ }
+
+ if (optind < argc) {
+ opts->inf = openFile(argv[optind], "r");
+ opts->infname = argv[optind];
+ } else {
+ opts->inf = stdin;
+ opts->infname = "<stdin>";
+ }
+
+ if (!opts->outf) {
+ opts->outf = stdout;
+ opts->outfname = "<stdout>";
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ opts_t opts;
+
+ init(argc, argv, &opts);
+ doxlabel(&opts);
+ return 0;
+}
--- /dev/null
+/* vim:set shiftwidth=4 ts=8: */
+
+/*************************************************************************
+ * Copyright (c) 2011 AT&T Intellectual Property
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors: See CVS logs. Details at http://www.graphviz.org/
+ *************************************************************************/
+
+#include "index.h"
+#include <stdio.h>
+#include <assert.h>
+#include "logic.h"
+#include "arith.h"
+#include "rectangle.h"
+
+#define Undefined(x) ((x)->boundary[0] > (x)->boundary[NUMDIMS])
+
+extern Rect_t CoverAll;
+
+/*-----------------------------------------------------------------------------
+| Initialize a rectangle to have all 0 coordinates.
+-----------------------------------------------------------------------------*/
+void InitRect(Rect_t * r)
+{
+ register int i;
+ for (i = 0; i < NUMSIDES; i++)
+ r->boundary[i] = 0;
+}
+
+/*-----------------------------------------------------------------------------
+| Return a rect whose first low side is higher than its opposite side -
+| interpreted as an undefined rect.
+-----------------------------------------------------------------------------*/
+Rect_t NullRect()
+{
+ Rect_t r;
+ register int i;
+
+ r.boundary[0] = 1;
+ r.boundary[NUMDIMS] = -1;
+ for (i = 1; i < NUMDIMS; i++)
+ r.boundary[i] = r.boundary[i + NUMDIMS] = 0;
+ return r;
+}
+
+#ifdef UNUSED
+/*-----------------------------------------------------------------------------
+| Fills in random coordinates in a rectangle.
+| The low side is guaranteed to be less than the high side.
+-----------------------------------------------------------------------------*/
+RandomRect(Rect_t * r)
+{
+ register int i, width;
+ for (i = 0; i < NUMDIMS; i++) {
+ /* width from 1 to 1000 / 4, more small ones */
+ width = rand() % (1000 / 4) + 1;
+
+ /* sprinkle a given size evenly but so they stay in [0,100] */
+ r->boundary[i] = rand() % (1000 - width); /* low side */
+ r->boundary[i + NUMDIMS] = r->boundary[i] + width; /* high side */
+ }
+}
+
+/*-----------------------------------------------------------------------------
+| Fill in the boundaries for a random search rectangle.
+| Pass in a pointer to a rect that contains all the data,
+| and a pointer to the rect to be filled in.
+| Generated rect is centered randomly anywhere in the data area,
+| and has size from 0 to the size of the data area in each dimension,
+| i.e. search rect can stick out beyond data area.
+-----------------------------------------------------------------------------*/
+SearchRect(Rect_t * search, Rect_t * data)
+{
+ register int i, j, size, center;
+
+ assert(search);
+ assert(data);
+
+ for (i = 0; i < NUMDIMS; i++) {
+ j = i + NUMDIMS; /* index for high side boundary */
+ if (data->boundary[i] > INT_MIN && data->boundary[j] < INT_MAX) {
+ size =
+ (rand() % (data->boundary[j] - data->boundary[i] + 1)) / 2;
+ center = data->boundary[i]
+ + rand() % (data->boundary[j] - data->boundary[i] + 1);
+ search->boundary[i] = center - size / 2;
+ search->boundary[j] = center + size / 2;
+ } else { /* some open boundary, search entire dimension */
+ search->boundary[i] = INT_MIN;
+ search->boundary[j] = INT_MAX;
+ }
+ }
+}
+#endif
+
+#ifdef RTDEBUG
+/*-----------------------------------------------------------------------------
+| Print rectangle lower upper bounds by dimension
+-----------------------------------------------------------------------------*/
+void PrintRect(Rect_t * r)
+{
+ register int i;
+ assert(r);
+ fprintf(stderr, "rect:");
+ for (i = 0; i < NUMDIMS; i++)
+ fprintf(stderr, "\t%d\t%d\n", r->boundary[i],
+ r->boundary[i + NUMDIMS]);
+}
+#endif
+
+/*-----------------------------------------------------------------------------
+| Calculate the n-dimensional area of a rectangle
+-----------------------------------------------------------------------------*/
+int RectArea(Rect_t * r)
+{
+ register int i, area;
+ assert(r);
+
+ if (Undefined(r))
+ return 0;
+
+ area = 1;
+ for (i = 0; i < NUMDIMS; i++) {
+ area *= r->boundary[i + NUMDIMS] - r->boundary[i];
+ }
+ return area;
+}
+
+/*-----------------------------------------------------------------------------
+| Combine two rectangles, make one that includes both.
+-----------------------------------------------------------------------------*/
+Rect_t CombineRect(Rect_t * r, Rect_t * rr)
+{
+ register int i, j;
+ Rect_t new;
+ assert(r && rr);
+
+ if (Undefined(r))
+ return *rr;
+ if (Undefined(rr))
+ return *r;
+
+ for (i = 0; i < NUMDIMS; i++) {
+ new.boundary[i] = MIN(r->boundary[i], rr->boundary[i]);
+ j = i + NUMDIMS;
+ new.boundary[j] = MAX(r->boundary[j], rr->boundary[j]);
+ }
+ return new;
+}
+
+/*-----------------------------------------------------------------------------
+| Decide whether two rectangles overlap.
+-----------------------------------------------------------------------------*/
+int Overlap(Rect_t * r, Rect_t * s)
+{
+ register int i, j;
+ assert(r && s);
+
+ for (i = 0; i < NUMDIMS; i++) {
+ j = i + NUMDIMS; /* index for high sides */
+ if (r->boundary[i] > s->boundary[j]
+ || s->boundary[i] > r->boundary[j])
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*-----------------------------------------------------------------------------
+| Decide whether rectangle r is contained in rectangle s.
+-----------------------------------------------------------------------------*/
+int Contained(Rect_t * r, Rect_t * s)
+{
+ register int i, j, result;
+ assert((int) r && (int) s);
+
+ /* undefined rect is contained in any other */
+ if (Undefined(r))
+ return TRUE;
+ /* no rect (except an undefined one) is contained in an undef rect */
+ if (Undefined(s))
+ return FALSE;
+
+ result = TRUE;
+ for (i = 0; i < NUMDIMS; i++) {
+ j = i + NUMDIMS; /* index for high sides */
+ result = result && r->boundary[i] >= s->boundary[i]
+ && r->boundary[j] <= s->boundary[j];
+ }
+ return result;
+}
--- /dev/null
+/* vim:set shiftwidth=4 ts=8: */
+
+/*************************************************************************
+ * Copyright (c) 2011 AT&T Intellectual Property
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors: See CVS logs. Details at http://www.graphviz.org/
+ *************************************************************************/
+
+#ifndef RECTANGLE_H
+#define RECTANGLE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Rect {
+ int boundary[NUMSIDES];
+} Rect_t;
+
+void InitRect(Rect_t * r);
+#ifdef RTDEBUG
+void PrintRect(Rect_t *);
+#endif
+int RectArea(Rect_t *);
+int Overlap(Rect_t *, Rect_t *);
+int Contained(Rect_t *, Rect_t *);
+Rect_t CombineRect(Rect_t *, Rect_t *);
+Rect_t NullRect();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*RECTANGLE_H */
--- /dev/null
+/* vim:set shiftwidth=4 ts=8: */
+
+/*************************************************************************
+ * Copyright (c) 2011 AT&T Intellectual Property
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors: See CVS logs. Details at http://www.graphviz.org/
+ *************************************************************************/
+
+#include "index.h"
+#include <stdio.h>
+#include <assert.h>
+#include "split.q.h"
+#include "logic.h"
+
+/* Forward declarations */
+static void MethodZero(RTree_t * rtp);
+static void InitPVars(RTree_t * rtp);
+static void LoadNodes(RTree_t * rtp, Node_t * n, Node_t * q,
+ struct PartitionVars *p);
+static void Classify(RTree_t * rtp, int i, int group);
+static void PickSeeds(RTree_t * rtp);
+static void GetBranches(RTree_t * rtp, Node_t * n, Branch_t * b);
+
+/*-----------------------------------------------------------------------------
+| Split a node.
+| Divides the nodes branches and the extra one between two nodes.
+| Old node is one of the new ones, and one really new one is created.
+| Tries more than one method for choosing a partition, uses best result.
+-----------------------------------------------------------------------------*/
+void SplitNode(RTree_t * rtp, Node_t * n, Branch_t * b, Node_t ** nn)
+{
+ register struct PartitionVars *p;
+ register int level;
+ int area;
+
+ assert(n);
+ assert(b);
+
+#ifdef RTDEBUG
+ fprintf(stderr, "Splitting:\n");
+ PrintNode(n);
+ fprintf(stderr, "new branch:\n");
+ PrintBranch(-1, b);
+#endif
+
+ if (rtp->StatFlag) {
+ if (rtp->Deleting)
+ rtp->DeSplitCount++;
+ else
+ rtp->InSplitCount++;
+ }
+
+ /* load all the branches into a buffer, initialize old node */
+ level = n->level;
+ GetBranches(rtp, n, b);
+
+#ifdef RTDEBUG
+ {
+ int i;
+ /* Indicate that a split is about to take place */
+ for (i = 0; i < NODECARD + 1; i++) {
+ PrintRect(&rtp->split.BranchBuf[i].rect);
+ }
+ PrintRect(&rtp->split.CoverSplit);
+ }
+#endif
+
+ /* find partition */
+ p = &rtp->split.Partitions[0];
+ MethodZero(rtp);
+
+ area = RectArea(&p->cover[0]) + RectArea(&p->cover[1]);
+
+ /* record how good the split was for statistics */
+ if (rtp->StatFlag && !rtp->Deleting && area)
+ rtp->SplitMeritSum += (float) rtp->split.CoverSplitArea / area;
+
+ /* put branches from buffer into 2 nodes according to chosen partition */
+ *nn = RTreeNewNode(rtp);
+ (*nn)->level = n->level = level;
+ LoadNodes(rtp, n, *nn, p);
+ assert(n->count + (*nn)->count == NODECARD + 1);
+
+#ifdef RTDEBUG
+ PrintPVars(p);
+ fprintf(stderr, "group 0:\n");
+ PrintNode(n);
+ fprintf(stderr, "group 1:\n");
+ PrintNode(*nn);
+ fprintf(stderr, "\n");
+#endif
+
+}
+
+/*-----------------------------------------------------------------------------
+| Load branch buffer with branches from full node plus the extra branch.
+-----------------------------------------------------------------------------*/
+static void GetBranches(RTree_t * rtp, Node_t * n, Branch_t * b)
+{
+ register int i;
+
+ assert(n);
+ assert(b);
+
+ /* load the branch buffer */
+ for (i = 0; i < NODECARD; i++) {
+ assert(n->branch[i].child); /* node should have every entry full */
+ rtp->split.BranchBuf[i] = n->branch[i];
+ }
+ rtp->split.BranchBuf[NODECARD] = *b;
+
+ /* calculate rect containing all in the set */
+ rtp->split.CoverSplit = rtp->split.BranchBuf[0].rect;
+ for (i = 1; i < NODECARD + 1; i++) {
+ rtp->split.CoverSplit = CombineRect(&rtp->split.CoverSplit,
+ &rtp->split.BranchBuf[i].rect);
+ }
+ rtp->split.CoverSplitArea = RectArea(&rtp->split.CoverSplit);
+
+ InitNode(n);
+}
+
+/*-----------------------------------------------------------------------------
+| Method #0 for choosing a partition:
+| As the seeds for the two groups, pick the two rects that would waste the
+| most area if covered by a single rectangle, i.e. evidently the worst pair
+| to have in the same group.
+| Of the remaining, one at a time is chosen to be put in one of the two groups.
+| The one chosen is the one with the greatest difference in area expansion
+| depending on which group - the rect most strongly attracted to one group
+| and repelled from the other.
+| If one group gets too full (more would force other group to violate min
+| fill requirement) then other group gets the rest.
+| These last are the ones that can go in either group most easily.
+-----------------------------------------------------------------------------*/
+static void MethodZero(RTree_t * rtp)
+{
+ register Rect_t *r;
+ register int i, growth0, growth1, diff, biggestDiff;
+ register int group, chosen, betterGroup;
+
+ InitPVars(rtp);
+ PickSeeds(rtp);
+
+ while (rtp->split.Partitions[0].count[0] +
+ rtp->split.Partitions[0].count[1] < NODECARD + 1 &&
+ rtp->split.Partitions[0].count[0] < NODECARD + 1 - rtp->MinFill
+ && rtp->split.Partitions[0].count[1] <
+ NODECARD + 1 - rtp->MinFill) {
+ biggestDiff = -1;
+ for (i = 0; i < NODECARD + 1; i++) {
+ if (!rtp->split.Partitions[0].taken[i]) {
+ Rect_t rect;
+ r = &rtp->split.BranchBuf[i].rect;
+ /* growth0 = RectArea(&CombineRect(r,
+ &rtp->split.Partitions[0].cover[0])) -
+ rtp->split.Partitions[0].area[0];
+ */
+ /* growth1 = RectArea(&CombineRect(r,
+ &rtp->split.Partitions[0].cover[1])) -
+ rtp->split.Partitions[0].area[1];
+ */
+ rect = CombineRect(r, &rtp->split.Partitions[0].cover[0]);
+ growth0 =
+ RectArea(&rect) - rtp->split.Partitions[0].area[0];
+ rect = CombineRect(r, &rtp->split.Partitions[0].cover[1]);
+ growth1 =
+ RectArea(&rect) - rtp->split.Partitions[0].area[1];
+ diff = growth1 - growth0;
+ if (diff >= 0)
+ group = 0;
+ else {
+ group = 1;
+ diff = -diff;
+ }
+
+ if (diff > biggestDiff) {
+ biggestDiff = diff;
+ chosen = i;
+ betterGroup = group;
+ } else if (diff == biggestDiff &&
+ rtp->split.Partitions[0].count[group] <
+ rtp->split.Partitions[0].count[betterGroup]) {
+ chosen = i;
+ betterGroup = group;
+ }
+ }
+ }
+ Classify(rtp, chosen, betterGroup);
+ }
+
+ /* if one group too full, put remaining rects in the other */
+ if (rtp->split.Partitions[0].count[0] +
+ rtp->split.Partitions[0].count[1] < NODECARD + 1) {
+ group = 0;
+ if (rtp->split.Partitions[0].count[0] >=
+ NODECARD + 1 - rtp->MinFill)
+ group = 1;
+ for (i = 0; i < NODECARD + 1; i++) {
+ if (!rtp->split.Partitions[0].taken[i])
+ Classify(rtp, i, group);
+ }
+ }
+
+ assert(rtp->split.Partitions[0].count[0] +
+ rtp->split.Partitions[0].count[1] == NODECARD + 1);
+ assert(rtp->split.Partitions[0].count[0] >= rtp->MinFill
+ && rtp->split.Partitions[0].count[1] >= rtp->MinFill);
+}
+
+/*-----------------------------------------------------------------------------
+| Pick two rects from set to be the first elements of the two groups.
+| Pick the two that waste the most area if covered by a single rectangle.
+-----------------------------------------------------------------------------*/
+static void PickSeeds(RTree_t * rtp)
+{
+ register int i, j, waste, worst, seed0, seed1;
+ int area[NODECARD + 1];
+
+ for (i = 0; i < NODECARD + 1; i++)
+ area[i] = RectArea(&rtp->split.BranchBuf[i].rect);
+
+ worst = -rtp->split.CoverSplitArea - 1;
+ for (i = 0; i < NODECARD; i++) {
+ for (j = i + 1; j < NODECARD + 1; j++) {
+ Rect_t rect;
+ /* waste = RectArea(&CombineRect(&rtp->split.BranchBuf[i].rect,
+ // &rtp->split.BranchBuf[j].rect)) - area[i] - area[j];
+ */
+ rect = CombineRect(&rtp->split.BranchBuf[i].rect,
+ &rtp->split.BranchBuf[j].rect);
+ waste = RectArea(&rect) - area[i] - area[j];
+ if (waste > worst) {
+ worst = waste;
+ seed0 = i;
+ seed1 = j;
+ }
+ }
+ }
+ Classify(rtp, seed0, 0);
+ Classify(rtp, seed1, 1);
+}
+
+/*-----------------------------------------------------------------------------
+| Put a branch in one of the groups.
+-----------------------------------------------------------------------------*/
+static void Classify(RTree_t * rtp, int i, int group)
+{
+
+ assert(!rtp->split.Partitions[0].taken[i]);
+
+ rtp->split.Partitions[0].partition[i] = group;
+ rtp->split.Partitions[0].taken[i] = TRUE;
+
+ if (rtp->split.Partitions[0].count[group] == 0)
+ rtp->split.Partitions[0].cover[group] =
+ rtp->split.BranchBuf[i].rect;
+ else
+ rtp->split.Partitions[0].cover[group] =
+ CombineRect(&rtp->split.BranchBuf[i].rect,
+ &rtp->split.Partitions[0].cover[group]);
+ rtp->split.Partitions[0].area[group] =
+ RectArea(&rtp->split.Partitions[0].cover[group]);
+ rtp->split.Partitions[0].count[group]++;
+
+# ifdef RTDEBUG
+ {
+ /* redraw entire group and its cover */
+ int j;
+ MFBSetColor(WHITE); /* cover is white */
+ PrintRect(&rtp->split.Partitions[0].cover[group]);
+ MFBSetColor(group + 3); /* group 0 green, group 1 blue */
+ for (j = 0; j < NODECARD + 1; j++) {
+ if (rtp->split.Partitions[0].taken[j] &&
+ rtp->split.Partitions[0].partition[j] == group)
+ PrintRect(&rtrtp->split.Partitions[0].BranchBuf[j].rect);
+ }
+ GraphChar();
+ }
+# endif
+}
+
+/*-----------------------------------------------------------------------------
+| Copy branches from the buffer into two nodes according to the partition.
+-----------------------------------------------------------------------------*/
+static void LoadNodes(RTree_t * rtp, Node_t * n, Node_t * q,
+ struct PartitionVars *p)
+{
+ register int i;
+ assert(n);
+ assert(q);
+ assert(p);
+
+ for (i = 0; i < NODECARD + 1; i++) {
+ assert(rtp->split.Partitions[0].partition[i] == 0 ||
+ rtp->split.Partitions[0].partition[i] == 1);
+ if (rtp->split.Partitions[0].partition[i] == 0)
+ AddBranch(rtp, &rtp->split.BranchBuf[i], n, NULL);
+ else if (rtp->split.Partitions[0].partition[i] == 1)
+ AddBranch(rtp, &rtp->split.BranchBuf[i], q, NULL);
+ }
+}
+
+/*-----------------------------------------------------------------------------
+| Initialize a PartitionVars structure.
+-----------------------------------------------------------------------------*/
+static void InitPVars(RTree_t * rtp)
+{
+ register int i;
+
+ rtp->split.Partitions[0].count[0] = rtp->split.Partitions[0].count[1] =
+ 0;
+ rtp->split.Partitions[0].cover[0] = rtp->split.Partitions[0].cover[1] =
+ NullRect();
+ rtp->split.Partitions[0].area[0] = rtp->split.Partitions[0].area[1] =
+ 0;
+ for (i = 0; i < NODECARD + 1; i++) {
+ rtp->split.Partitions[0].taken[i] = FALSE;
+ rtp->split.Partitions[0].partition[i] = -1;
+ }
+}
+
+#ifdef RTDEBUG
+
+/*-----------------------------------------------------------------------------
+| Print out data for a partition from PartitionVars struct.
+-----------------------------------------------------------------------------*/
+PrintPVars(RTree_t * rtp)
+{
+ register int i;
+
+ fprintf(stderr, "\npartition:\n");
+ for (i = 0; i < NODECARD + 1; i++) {
+ fprintf(stderr, "%3d\t", i);
+ }
+ fprintf(stderr, "\n");
+ for (i = 0; i < NODECARD + 1; i++) {
+ if (rtp->split.Partitions[0].taken[i])
+ fprintf(stderr, " t\t");
+ else
+ fprintf(stderr, "\t");
+ }
+ fprintf(stderr, "\n");
+ for (i = 0; i < NODECARD + 1; i++) {
+ fprintf(stderr, "%3d\t", rtp->split.Partitions[0].partition[i]);
+ }
+ fprintf(stderr, "\n");
+
+ fprintf(stderr, "count[0] = %d area = %d\n",
+ rtp->split.Partitions[0].count[0],
+ rtp->split.Partitions[0].area[0]);
+ fprintf(stderr, "count[1] = %d area = %d\n",
+ rtp->split.Partitions[0].count[1],
+ rtp->split.Partitions[0].area[1]);
+ if (rtp->split.Partitions[0].area[0] +
+ rtp->split.Partitions[0].area[1] > 0) {
+ fprintf(stderr, "total area = %d effectiveness = %3.2f\n",
+ rtp->split.Partitions[0].area[0] +
+ rtp->split.Partitions[0].area[1],
+ (float) rtp->split.CoverSplitArea /
+ (rtp->split.Partitions[0].area[0] +
+ rtp->split.Partitions[0].area[1]));
+ }
+ fprintf(stderr, "cover[0]:\n");
+ PrintRect(&rtp->split.Partitions[0].cover[0]);
+
+ fprintf(stderr, "cover[1]:\n");
+ PrintRect(&rtp->split.Partitions[0].cover[1]);
+}
+#endif
--- /dev/null
+/* vim:set shiftwidth=4 ts=8: */
+
+/*************************************************************************
+ * Copyright (c) 2011 AT&T Intellectual Property
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors: See CVS logs. Details at http://www.graphviz.org/
+ *************************************************************************/
+
+#ifndef SPLIT_Q_H
+#define SPLIT_Q_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*-----------------------------------------------------------------------------
+| Definitions and global variables.
+-----------------------------------------------------------------------------*/
+#include <rectangle.h>
+#include <index.h>
+
+#ifndef METHODS
+#define METHODS 1
+#endif /*METHODS*/
+/* variables for finding a partition */
+ struct PartitionVars {
+ int partition[NODECARD + 1];
+ int taken[NODECARD + 1];
+ int count[2];
+ struct Rect cover[2];
+ int area[2];
+};
+
+typedef struct split_q_s {
+ struct Branch BranchBuf[NODECARD + 1];
+ struct Rect CoverSplit;
+ int CoverSplitArea;
+ struct PartitionVars Partitions[METHODS];
+} SplitQ_t;
+
+void SplitNode(RTree_t *, Node_t *, Branch_t *, Node_t **);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*SPLIT_Q_H */
--- /dev/null
+/* vim:set shiftwidth=4 ts=8: */
+
+/*************************************************************************
+ * Copyright (c) 2011 AT&T Intellectual Property
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors: See CVS logs. Details at http://www.graphviz.org/
+ *************************************************************************/
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#define XLABEL_INT
+#include <xlabels.h>
+#include <memory.h>
+
+extern int Verbose;
+
+static int icompare(Dt_t *, Void_t *, Void_t *, Dtdisc_t *);
+
+Dtdisc_t Hdisc = { offsetof(HDict_t, key), sizeof(int), -1, 0, 0,
+ icompare, 0, 0, 0
+};
+
+static int icompare(Dt_t * dt, Void_t * v1, Void_t * v2, Dtdisc_t * disc)
+{
+ int k1 = *((int *) v1), k2 = *((int *) v2);
+ return k1 - k2;
+}
+
+static XLabels_t *xlnew(object_t * objs, int n_objs,
+ xlabel_t * lbls, int n_lbls,
+ label_params_t * params)
+{
+ XLabels_t *xlp;
+
+ xlp = NEW(XLabels_t);
+
+ /* used to load the rtree in hilbert space filling curve order */
+ if (!(xlp->hdx = dtopen(&Hdisc, Dtobag))) {
+ fprintf(stderr, "out of memory\n");
+ goto bad;
+ }
+
+ /* for querying intersection candidates */
+ if (!(xlp->spdx = RTreeOpen())) {
+ fprintf(stderr, "out of memory\n");
+ goto bad;
+ }
+ /* save arg pointers in the handle */
+ xlp->objs = objs;
+ xlp->n_objs = n_objs;
+ xlp->lbls = lbls;
+ xlp->n_lbls = n_lbls;
+ xlp->params = params;
+
+ return xlp;
+
+ bad:
+ if (xlp->hdx)
+ dtclose(xlp->hdx);
+ if (xlp->spdx)
+ RTreeClose(xlp->spdx);
+ free(xlp);
+ return 0;
+}
+
+static void xlfree(XLabels_t * xlp)
+{
+ RTreeClose(xlp->spdx);
+ free(xlp);
+ return;
+}
+
+/***************************************************************************/
+
+/*
+ * floorlog2 - largest base 2 integer logarithm less than n
+ * http://en.wikipedia.org/wiki/Binary_logarithm
+ * ultimately from http://www.hackersdelight.org/
+ */
+static int floorLog2(unsigned int n)
+{
+ int pos = 0;
+
+ if (n == 0)
+ return -1;
+
+ if (n >= 1 << 16) {
+ n >>= 16;
+ pos += 16;
+ }
+ if (n >= 1 << 8) {
+ n >>= 8;
+ pos += 8;
+ }
+ if (n >= 1 << 4) {
+ n >>= 4;
+ pos += 4;
+ }
+ if (n >= 1 << 2) {
+ n >>= 2;
+ pos += 2;
+ }
+ if (n >= 1 << 1) {
+ pos += 1;
+ }
+ return pos;
+}
+
+/*
+ * determine the order(depth) of the hilbert sfc so that we satisfy the
+ * precondition of hd_hil_s_from_xy()
+ */
+unsigned int xlhorder(XLabels_t * xlp)
+{
+ double maxx = xlp->params->bb.UR.x, maxy = xlp->params->bb.UR.y;
+ return floorLog2(maxx > maxy ? maxx : maxy) + 1;
+}
+
+/* from http://www.hackersdelight.org/ site for the book by Henry S Warren */
+/*
+ * precondition
+ * pow(2, n) >= max(p.x, p.y)
+ */
+/* adapted from lams1.c
+Given the "order" n of a Hilbert curve and coordinates x and y, this
+program computes the length s of the curve from the origin to (x, y).
+The square that the Hilbert curve traverses is of size 2**n by 2**n.
+ The method is that given in [Lam&Shap], described by the following
+table. Here i = n-1 for the most significant bit of x and y, and i = 0
+for the least significant bits.
+
+ x[i] y[i] | s[2i+1:2i] x y
+ -----------|-------------------
+ 0 0 | 00 y x
+ 0 1 | 01 x y
+ 1 0 | 11 ~y ~x
+ 1 1 | 10 x y
+
+To use this table, start at the most significant bits of x and y
+(i = n - 1). If they are both 0 (first row), set the most significant
+two bits of s to 00 and interchange x and y. (Actually, it is only
+necessary to interchange the remaining bits of x and y.) If the most
+significant bits of x and y are 10 (third row), output 11, interchange x
+and y, and complement x and y.
+ Then, consider the next most significant bits of x and y (which may
+have been changed by this process), and select the appropriate row of
+the table to determine the next two bits of s, and how to change x and
+y. Continue until the least significant bits of x and y have been
+processed. */
+
+static unsigned int hd_hil_s_from_xy(point p, int n)
+{
+ int i, x = p.x, y = p.y, xi, yi;
+ unsigned s;
+
+ s = 0; /* Initialize. */
+ for (i = n - 1; i >= 0; i--) {
+ xi = (x >> i) & 1; /* Get bit i of x. */
+ yi = (y >> i) & 1; /* Get bit i of y. */
+ s = 4 * s + 2 * xi + (xi ^ yi); /* Append two bits to s. */
+
+ x = x ^ y; /* These 3 lines swap */
+ y = y ^ (x & (yi - 1)); /* x and y if yi = 0. */
+ x = x ^ y;
+ x = x ^ (-xi & (yi - 1)); /* Complement x and y if */
+ y = y ^ (-xi & (yi - 1)); /* xi = 1 and yi = 0. */
+ }
+ return s;
+}
+
+/* intersection test from
+ * from Real-Time Collision Detection 4.2.1 by Christer Ericson
+ * intersection area from
+ * http://stackoverflow.com/questions/4549544/total-area-of-intersecting-rectangles
+*/
+static double aabbaabb(Rect_t * r, Rect_t * s)
+{
+ /* per dimension if( max < omin || min > omax) */
+ double iminx, iminy, imaxx, imaxy;
+ if (r->boundary[2] < s->boundary[0] || r->boundary[0] > s->boundary[2])
+ return 0;
+ if (r->boundary[3] < s->boundary[1] || r->boundary[1] > s->boundary[3])
+ return 0;
+
+ /* if we get here we have an intersection */
+
+ /* rightmost left edge of the 2 rectangles */
+ iminx =
+ r->boundary[0] > s->boundary[0] ? r->boundary[0] : s->boundary[0];
+ /* upmost bottom edge */
+ iminy =
+ r->boundary[1] > s->boundary[1] ? r->boundary[1] : s->boundary[1];
+ /* leftmost right edge */
+ imaxx =
+ r->boundary[2] < s->boundary[2] ? r->boundary[2] : s->boundary[2];
+ /* downmost top edge */
+ imaxy =
+ r->boundary[3] < s->boundary[3] ? r->boundary[3] : s->boundary[3];
+ return (imaxx - iminx) * (imaxy - iminy);
+}
+
+/*fill in rectangle from the object */
+static void objp2rect(object_t * op, Rect_t * r)
+{
+ r->boundary[0] = op->pos.x;
+ r->boundary[1] = op->pos.y;
+ r->boundary[2] = op->pos.x + op->sz.x;
+ r->boundary[3] = op->pos.y + op->sz.y;
+ return;
+}
+
+static void objplp2rect(object_t * objp, Rect_t * r)
+{
+ xlabel_t *lp = objp->lbl;
+ r->boundary[0] = lp->pos.x;
+ r->boundary[1] = lp->pos.y;
+ r->boundary[2] = lp->pos.x + lp->sz.x;
+ r->boundary[3] = lp->pos.y + lp->sz.y;
+ return;
+}
+
+/* compute boundary that encloses all possible label boundaries */
+static Rect_t objplpmks(XLabels_t * xlp, object_t * objp)
+{
+ Rect_t rect;
+ pointf p;
+
+ p.x = p.y = 0.0;
+ if (objp->lbl)
+ p = objp->lbl->sz;
+
+ rect.boundary[0] = (int) floor(objp->pos.x - p.x);
+ rect.boundary[1] = (int) floor(objp->pos.y - p.y);
+
+ rect.boundary[2] = (int) ceil(objp->pos.x + objp->sz.x + p.x);
+ assert(rect.boundary[2] < INT_MAX);
+ rect.boundary[3] = (int) ceil(objp->pos.y + objp->sz.y + p.y);
+ assert(rect.boundary[3] < INT_MAX);
+
+ return rect;
+}
+
+/* determine the position clp will occupy in intrsx[] */
+static int getintrsxi(XLabels_t * xlp, object_t * op, object_t * cp)
+{
+ int i = -1;
+ xlabel_t *lp = op->lbl, *clp = cp->lbl;
+ assert(lp != clp);
+
+ if (lp->set == 0 || clp->set == 0)
+ return i;
+ if ((op->pos.x == 0.0 && op->pos.y == 0.0) ||
+ (cp->pos.x == 0.0 && cp->pos.y == 0.0))
+ return i;
+
+ if (cp->pos.y < op->pos.y)
+ if (cp->pos.x < op->pos.x)
+ i = XLPXPY;
+ else if (cp->pos.x > op->pos.x)
+ i = XLNXPY;
+ else
+ i = XLCXPY;
+ else if (cp->pos.y > op->pos.y)
+ if (cp->pos.x < op->pos.x)
+ i = XLPXNY;
+ else if (cp->pos.x > op->pos.x)
+ i = XLNXNY;
+ else
+ i = XLCXNY;
+ else if (cp->pos.x < op->pos.x)
+ i = XLPXCY;
+ else if (cp->pos.x > op->pos.x)
+ i = XLNXCY;
+
+ return i;
+
+}
+
+/* record the intersecting objects label */
+static double
+recordointrsx(XLabels_t * xlp, object_t * op, object_t * cp, Rect_t * rp,
+ double a, object_t * intrsx[XLNBR])
+{
+ int i = getintrsxi(xlp, op, cp);
+ if (i < 0)
+ i = 5;
+ if (intrsx[i] != NULL) {
+ double sa, maxa = 0.0;
+ Rect_t srect;
+ /* keep maximally overlapping object */
+ objp2rect(intrsx[i], &srect);
+ sa = aabbaabb(rp, &srect);
+ if (sa > a)
+ maxa = sa;
+ /*keep maximally overlapping label */
+ if (intrsx[i]->lbl) {
+ objplp2rect(intrsx[i], &srect);
+ sa = aabbaabb(rp, &srect);
+ if (sa > a)
+ maxa = sa > maxa ? sa : maxa;
+ }
+ if (maxa > 0.0)
+ return maxa;
+ /*replace overlapping label/object pair */
+ intrsx[i] = cp;
+ return a;
+ }
+ intrsx[i] = cp;
+ return a;
+}
+
+/* record the intersecting label */
+static double
+recordlintrsx(XLabels_t * xlp, object_t * op, object_t * cp, Rect_t * rp,
+ double a, object_t * intrsx[XLNBR])
+{
+ int i = getintrsxi(xlp, op, cp);
+ if (i < 0)
+ i = 5;
+ if (intrsx[i] != NULL) {
+ double sa, maxa = 0.0;
+ Rect_t srect;
+ /* keep maximally overlapping object */
+ objp2rect(intrsx[i], &srect);
+ sa = aabbaabb(rp, &srect);
+ if (sa > a)
+ maxa = sa;
+ /*keep maximally overlapping label */
+ if (intrsx[i]->lbl) {
+ objplp2rect(intrsx[i], &srect);
+ sa = aabbaabb(rp, &srect);
+ if (sa > a)
+ maxa = sa > maxa ? sa : maxa;
+ }
+ if (maxa > 0.0)
+ return maxa;
+ /*replace overlapping label/object pair */
+ intrsx[i] = cp;
+ return a;
+ }
+ intrsx[i] = cp;
+ return a;
+}
+
+/* find the objects and labels intersecting lp */
+static BestPos_t
+xlintersections(XLabels_t * xlp, object_t * objp, object_t * intrsx[XLNBR])
+{
+ LeafList_t *ilp, *llp;
+ Rect_t rect, srect;
+ BestPos_t bp;
+
+ assert(objp->lbl);
+
+ bp.n = 0;
+ bp.area = 0.0;
+ bp.pos = objp->lbl->pos;
+
+ objplp2rect(objp, &rect);
+
+ llp = RTreeSearch(xlp->spdx, xlp->spdx->root, &rect);
+ if (!llp)
+ return bp;
+
+ for (ilp = llp; ilp; ilp = ilp->next) {
+ double a, ra;
+ object_t *cp = ilp->leaf->data;
+
+ if (cp == objp)
+ continue;
+
+ /*label-object intersect */
+ objp2rect(cp, &srect);
+ a = aabbaabb(&rect, &srect);
+ if (a > 0.0) {
+ ra = recordointrsx(xlp, objp, cp, &rect, a, intrsx);
+ bp.n++;
+ bp.area += ra;
+ }
+ /*label-label intersect */
+ if (!cp->lbl || !cp->lbl->set)
+ continue;
+ objplp2rect(cp, &srect);
+ a = aabbaabb(&rect, &srect);
+ if (a > 0.0) {
+ recordlintrsx(xlp, objp, cp, &rect, a, intrsx);
+ bp.n++;
+ bp.area += a;
+ }
+ }
+ RTreeLeafListFree(llp);
+ return bp;
+}
+
+/*
+ * xladjust - find a label position
+ * the individual tests at the top are intended to place a preference order
+ * on the position
+ */
+static BestPos_t xladjust(XLabels_t * xlp, object_t * objp)
+{
+ xlabel_t *lp = objp->lbl;
+ double xincr = ((2 * lp->sz.x) + objp->sz.x) / XLXDENOM;
+ double yincr = ((2 * lp->sz.y) + objp->sz.y) / XLYDENOM;
+ object_t *intrsx[XLNBR];
+ BestPos_t bp, nbp;
+
+ assert(objp->lbl);
+
+ memset(intrsx, 0, sizeof(intrsx));
+
+ /*x left */
+ lp->pos.x = objp->pos.x - lp->sz.x;
+ /*top */
+ lp->pos.y = objp->pos.y + objp->sz.y;
+ bp = xlintersections(xlp, objp, intrsx);
+ if (bp.n == 0)
+ return bp;
+ /*mid */
+ lp->pos.y = objp->pos.y;
+ nbp = xlintersections(xlp, objp, intrsx);
+ if (nbp.n == 0)
+ return nbp;
+ if (nbp.area < bp.area)
+ bp = nbp;
+ /*bottom */
+ lp->pos.y = objp->pos.y - lp->sz.y;
+ nbp = xlintersections(xlp, objp, intrsx);
+ if (nbp.n == 0)
+ return nbp;
+ if (nbp.area < bp.area)
+ bp = nbp;
+
+ /*x mid */
+ lp->pos.x = objp->pos.x;
+ /*tobjp */
+ lp->pos.y = objp->pos.y + objp->sz.y;
+ nbp = xlintersections(xlp, objp, intrsx);
+ if (nbp.n == 0)
+ return nbp;
+ if (nbp.area < bp.area)
+ bp = nbp;
+ /*bottom */
+ lp->pos.y = objp->pos.y - lp->sz.y;
+ nbp = xlintersections(xlp, objp, intrsx);
+ if (nbp.n == 0)
+ return nbp;
+ if (nbp.area < bp.area)
+ bp = nbp;
+
+ /*x right */
+ lp->pos.x = objp->pos.x + objp->sz.x;
+ /*top */
+ lp->pos.y = objp->pos.y + objp->sz.y;
+ nbp = xlintersections(xlp, objp, intrsx);
+ if (nbp.n == 0)
+ return nbp;
+ if (nbp.area < bp.area)
+ bp = nbp;
+ /*mid */
+ lp->pos.y = objp->pos.y;
+ nbp = xlintersections(xlp, objp, intrsx);
+ if (nbp.n == 0)
+ return nbp;
+ if (nbp.area < bp.area)
+ bp = nbp;
+ /*bottom */
+ lp->pos.y = objp->pos.y - lp->sz.y;
+ nbp = xlintersections(xlp, objp, intrsx);
+ if (nbp.n == 0)
+ return nbp;
+ if (nbp.area < bp.area)
+ bp = nbp;
+
+ /*sliding from top left */
+ if (intrsx[XLPXNY] || intrsx[XLCXNY] || intrsx[XLNXNY] || intrsx[XLPXCY] || intrsx[XLPXPY]) { /* have to move */
+ if (!intrsx[XLCXNY] && !intrsx[XLNXNY]) { /* some room right? */
+ /* slide along upper edge */
+ for (lp->pos.x = objp->pos.x - lp->sz.x,
+ lp->pos.y = objp->pos.y + objp->sz.y;
+ lp->pos.x <= (objp->pos.x + objp->sz.x);
+ lp->pos.x += xincr) {
+ nbp = xlintersections(xlp, objp, intrsx);
+ if (nbp.n == 0)
+ return nbp;
+ if (nbp.area < bp.area)
+ bp = nbp;
+ }
+ }
+ if (!intrsx[XLPXCY] && !intrsx[XLPXPY]) { /* some room down? */
+ /* slide down left edge */
+ for (lp->pos.x = objp->pos.x - lp->sz.x,
+ lp->pos.y = objp->pos.y + objp->sz.y;
+ lp->pos.y >= (objp->pos.y - lp->sz.y);
+ lp->pos.y -= yincr) {
+ nbp = xlintersections(xlp, objp, intrsx);
+ if (nbp.n == 0)
+ return nbp;
+ if (nbp.area < bp.area)
+ bp = nbp;
+
+ }
+ }
+ }
+
+ /*sliding from bottom right */
+ lp->pos.x = objp->pos.x + objp->sz.x;
+ lp->pos.y = objp->pos.y - lp->sz.y;
+ if (intrsx[XLNXPY] || intrsx[XLCXPY] || intrsx[XLPXPY] || intrsx[XLNXCY] || intrsx[XLNXNY]) { /* have to move */
+ if (!intrsx[XLCXPY] && !intrsx[XLPXPY]) { /* some room left? */
+ /* slide along lower edge */
+ for (lp->pos.x = objp->pos.x + objp->sz.x,
+ lp->pos.y = objp->pos.y - lp->sz.y;
+ lp->pos.x >= (objp->pos.x - lp->sz.x);
+ lp->pos.x -= xincr) {
+ nbp = xlintersections(xlp, objp, intrsx);
+ if (nbp.n == 0)
+ return nbp;
+ if (nbp.area < bp.area)
+ bp = nbp;
+ }
+ }
+ if (!intrsx[XLNXCY] && !intrsx[XLNXNY]) { /* some room up? */
+ /* slide up right edge */
+ for (lp->pos.x = objp->pos.x + objp->sz.x,
+ lp->pos.y = objp->pos.y - lp->sz.y;
+ lp->pos.y <= (objp->pos.y + objp->sz.y);
+ lp->pos.y += yincr) {
+ nbp = xlintersections(xlp, objp, intrsx);
+ if (nbp.n == 0)
+ return nbp;
+ if (nbp.area < bp.area)
+ bp = nbp;
+ }
+ }
+ }
+ return bp;
+}
+
+/* load the hilbert sfc keyed tree */
+static int xlhdxload(XLabels_t * xlp)
+{
+ int i;
+ int order = xlhorder(xlp);
+
+ for (i = 0; i < xlp->n_objs; i++) {
+ HDict_t *hp;
+ point pi;
+
+ hp = NEW(HDict_t);
+
+ hp->d.data = &xlp->objs[i];
+ hp->d.rect = objplpmks(xlp, &xlp->objs[i]);
+ /* center of the labeling area */
+ pi.x = hp->d.rect.boundary[0] +
+ (hp->d.rect.boundary[2] - hp->d.rect.boundary[0]) / 2;
+ pi.y = hp->d.rect.boundary[1] +
+ (hp->d.rect.boundary[3] - hp->d.rect.boundary[1]) / 2;
+
+ hp->key = hd_hil_s_from_xy(pi, order);
+
+ if (dtsearch(xlp->hdx, hp) != 0)
+ continue;
+ if (!(dtinsert(xlp->hdx, hp)))
+ return -1;
+ }
+ return 0;
+}
+
+static int xlspdxload(XLabels_t * xlp)
+{
+ HDict_t *op;
+
+ for (op = dtfirst(xlp->hdx); op; op = dtnext(xlp->hdx, op)) {
+ /* tree rectangle data node lvl */
+ RTreeInsert(xlp->spdx, &op->d.rect, op->d.data, &xlp->spdx->root,
+ 0);
+ }
+ return 0;
+}
+
+static int xlinitialize(XLabels_t * xlp)
+{
+ int r;
+ if ((r = xlhdxload(xlp)) < 0)
+ return r;
+ if ((r = xlspdxload(xlp)) < 0)
+ return r;
+ return dtclose(xlp->hdx);
+}
+
+int
+placeLabels(object_t * objs, int n_objs,
+ xlabel_t * lbls, int n_lbls, label_params_t * params)
+{
+ int r, i;
+ BestPos_t bp;
+ XLabels_t *xlp = xlnew(objs, n_objs, lbls, n_lbls, params);
+ if ((r = xlinitialize(xlp)) < 0)
+ return r;
+
+ /* Place xlabel_t* lp near lp->obj so that the rectangle whose lower-left
+ * corner is lp->pos, and size is lp->sz does not intersect any object
+ * in objs (by convention, an object consisting of a single point
+ * intersects nothing) nor any other label, if possible. On input,
+ * lp->set is 0.
+ *
+ * On output, any label with a position should have this stored in
+ * lp->pos and have lp->set non-zero.
+ *
+ * If params->force is true, all labels must be positioned, even if
+ * overlaps are necessary.
+ *
+ * Return 0 if all labels could be placed without overlap;
+ * non-zero otherwise.
+ */
+ r = 0;
+ for (i = 0; i < n_objs; i++) {
+ if (objs[i].lbl == 0)
+ continue;
+ bp = xladjust(xlp, &objs[i]);
+ if (bp.n == 0) {
+ objs[i].lbl->set = 1;
+ } else if (params->force == 1) {
+ objs[i].lbl->pos.x = bp.pos.x;
+ objs[i].lbl->pos.y = bp.pos.y;
+ objs[i].lbl->set = 1;
+ } else {
+ r = 1;
+ }
+ }
+ xlfree(xlp);
+ return r;
+}
--- /dev/null
+/* vim:set shiftwidth=4 ts=8: */
+
+/*************************************************************************
+ * Copyright (c) 2011 AT&T Intellectual Property
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors: See CVS logs. Details at http://www.graphviz.org/
+ *************************************************************************/
+
+#ifndef XLABELS_H
+#define XLABELS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <geom.h>
+
+typedef struct {
+ pointf sz; /* Size of label (input) */
+ pointf pos; /* Position of lower-left corner of label (output) */
+ void *lbl; /* Pointer to label in the graph */
+ unsigned char set; /* True if the position has been set (input/output) */
+} xlabel_t;
+
+typedef struct {
+ pointf pos; /* Position of lower-left corner of object */
+ pointf sz; /* Size of object; may be zero for a point */
+ xlabel_t *lbl; /* Label attached to object, or NULL */
+} object_t;
+
+typedef struct {
+ boxf bb; /* Bounding box of all objects */
+ unsigned char force; /* If true, all labels must be placed */
+} label_params_t;
+
+int placeLabels(object_t * objs, int n_objs,
+ xlabel_t * lbls, int n_lbls, label_params_t * params);
+
+#ifdef XLABEL_INT
+#include <index.h>
+#include <logic.h>
+#include <cdt.h>
+
+#ifndef XLNDSCALE
+#define XLNDSCALE 72.0
+#endif /*XLNDSCALE*/
+#ifndef XLNBR
+#define XLNBR 9
+#endif /*XLNBR*/
+#ifndef XLXDENOM
+#define XLXDENOM 8
+#endif /*XLXDENOM*/
+#ifndef XLYDENOM
+#define XLYDENOM 2
+#endif /*XLYDENOM*/
+#define XLNBR 9
+#define XLCNR 4
+#define XLNDSCALE 72.0
+#define XLODCR -1
+// indexes of neighbors in certain arrays
+// the node of interest is usually in node 4
+// 6 7 8
+// 3 4 5
+// 0 1 2
+#define XLPXPY 0
+#define XLCXPY 1
+#define XLNXPY 2
+#define XLPXCY 3
+#define XLCXCY 4
+#define XLNXCY 5
+#define XLPXNY 6
+#define XLCXNY 7
+#define XLNXNY 8
+ typedef struct best_p_s {
+ int n;
+ double area;
+ pointf pos;
+} BestPos_t;
+
+typedef struct obyh {
+ Dtlink_t link;
+ int key;
+ Leaf_t d;
+} HDict_t;
+
+typedef struct XLabels_s {
+ object_t *objs;
+ int n_objs;
+ xlabel_t *lbls;
+ int n_lbls;
+ label_params_t *params;
+
+ Dt_t *hdx; // splay tree keyed with hilbert spatial codes
+ RTree_t *spdx; // rtree
+
+} XLabels_t;
+
+#endif /* XLABEL_INT */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*XLABELS_H */