74
81
static polygon_t p_octagon = { FALSE, 1, 8, 0., 0., 0. };
75
82
static polygon_t p_note = { FALSE, 1, 4, 0., 0., 0., DOGEAR };
76
83
static polygon_t p_tab = { FALSE, 1, 4, 0., 0., 0., TAB };
84
static polygon_t p_folder = { FALSE, 1, 4, 0., 0., 0., FOLDER };
77
85
static polygon_t p_box3d = { FALSE, 1, 4, 0., 0., 0., BOX3D };
78
86
static polygon_t p_component = { FALSE, 1, 4, 0., 0., 0., COMPONENT };
627
692
static void poly_init(node_t * n)
694
pointf dimen, min_bb, bb;
632
697
pointf *vertices;
634
double temp, alpha, beta, gamma, delta;
699
double temp, alpha, beta, gamma;
635
700
double orientation, distortion, skew;
636
701
double sectorangle, sidelength, skewdist, gdistortion, gskew;
637
702
double angle, sinx, cosx, xmax, ymax, scalex, scaley;
638
703
double width, height, marginx, marginy;
639
704
int regular, peripheries, sides;
705
int i, j, outp, labelloc;
641
706
polygon_t *poly = NEW(polygon_t);
643
708
regular = ND_shape(n)->polygon->regular;
731
804
GD_has_images(n->graph) = TRUE;
805
imagesize.x += 2; /* some fixed padding */
734
if (mapbool(late_string(n, N_fixed, "false"))) {
735
if ((width < dimen.x) || (height < dimen.y))
737
"node '%s', graph '%s' size too small for label\n",
738
n->name, n->graph->name);
739
dimen.x = dimen.y = 0;
742
dimen.x = MAX(dimen.x, imagesize.x+2);
743
dimen.y = MAX(dimen.y, imagesize.y+2);
747
if ((temp = GD_drawing(n->graph)->quantum) > 0.0) {
749
dimen.x = quant(dimen.x, temp);
750
dimen.y = quant(dimen.y, temp);
753
/* If regular, make label dimensions the same.
754
* Need this to guarantee final node size is regular.
757
dimen.x = dimen.y = MAX(dimen.x, dimen.y);
810
/* initialize node bb to labelsize */
811
bb.x = MAX(dimen.x, imagesize.x);
812
bb.y = MAX(dimen.y, imagesize.y);
760
814
/* I don't know how to distort or skew ellipses in postscript */
761
815
/* Convert request to a polygon with a large number of sides */
766
/* add extra padding to allow for the shape */
768
/* for ellipses, add padding based on the smaller radii */
769
if (dimen.y > dimen.x)
770
temp = dimen.x * (sqrt(2.) - 1.);
772
temp = dimen.y * (sqrt(2.) - 1.);
775
} else if (sides == 4 && (ROUND(orientation) % 90) == 0
820
/* extra sizing depends on if label is centered vertically */
821
p = agget(n, "labelloc");
822
if (p && p[0] == 't')
824
else if (p && p[0] == 'b')
829
if (sides == 4 && (ROUND(orientation) % 90) == 0
776
830
&& distortion == 0. && skew == 0.) {
777
831
/* for regular boxes the fit should be exact */
779
/* for all other polygon shapes, compute the inner ellipse
833
/* for all other shapes, compute the inner ellipse
780
834
and then pad for that */
781
temp = cos(PI / sides);
784
/* add padding based on the smaller radii */
785
if (dimen.y > dimen.x)
786
temp = dimen.x * (sqrt(2.) - 1.);
788
temp = dimen.y * (sqrt(2.) - 1.);
836
/* if there is height to spare and the label is centered vertically */
837
if (height > temp && labelloc == 0) {
838
bb.x *= sqrt(1. / (1. - SQR(bb.y / height)));
847
temp = cos(M_PI / sides);
850
/* FIXME - for odd-sided polygons, e.g. triangles, there
851
would be a better fit with some vertical adjustment of the shape */
856
/* at this point, bb is the minimum size of node that can hold the label */
793
859
/* increase node size to width/height if needed */
794
bb.x = width = MAX(width, dimen.x);
795
bb.y = height = MAX(height, dimen.y);
797
/* adjust text justification */
860
if (mapbool(late_string(n, N_fixed, "false"))) {
861
if ((width < bb.x) || (height < bb.y))
863
"node '%s', graph '%s' size too small for label\n",
864
n->name, n->graph->name);
869
bb.x = width = MAX(width, bb.x);
870
bb.y = height = MAX(height, bb.y);
873
/* If regular, make dimensions the same.
874
* Need this to guarantee final node size is regular.
877
bb.x = bb.y = MAX(bb.x, bb.y);
880
/* adjust text horizontal justification */
798
881
if (!mapbool(late_string(n, N_nojustify, "false"))) {
799
ND_label(n)->d.x = bb.x - dimen.x;
800
ND_label(n)->d.y = bb.y - dimen.y;
882
temp = bb.x - min_bb.x;
883
if (dimen.x < imagesize.x)
884
temp += imagesize.x - dimen.x;
886
ND_label(n)->d.x = temp;
889
/* adjust text vertical location */
890
temp = bb.y - min_bb.y;
891
if (dimen.y < imagesize.y)
892
temp += imagesize.y - dimen.y;
895
ND_label(n)->d.y = -temp;
896
else if (labelloc > 0)
897
ND_label(n)->d.y = temp;
899
ND_label(n)->d.y = 0;
803
902
outp = peripheries;
1523
1613
static void point_init(node_t * n)
1529
for (ptr = Shapes; ptr->name; ptr++)
1530
if (streq(ptr->name, "point")) {
1537
/* adjust label to "" */
1540
ND_label(n) = NEW(textlabel_t); /* allocate empty label that can be freed later */
1541
ND_label(n)->text = strdup("");
1615
polygon_t *poly = NEW(polygon_t);
1616
int sides, outp, peripheries = ND_shape(n)->polygon->peripheries;
1618
pointf P, *vertices;
1543
1622
/* set width and height, and make them equal
1544
1623
* if user has set weight or height, use it.
1545
1624
* if both are set, use smallest.
1546
1625
* if neither, use default
1548
if (ATTR_SET(N_width, n)) {
1549
if (ATTR_SET(N_height, n)) {
1550
ND_width(n) = ND_height(n) = MIN(ND_width(n), ND_height(n));
1552
ND_height(n) = ND_width(n);
1553
} else if (ATTR_SET(N_height, n)) {
1554
ND_width(n) = ND_height(n);
1627
w = late_double(n, N_width, MAXDOUBLE, MIN_POINT);
1628
h = late_double(n, N_height, MAXDOUBLE, MIN_POINT);
1630
if ((w == MAXDOUBLE) && (h == MAXDOUBLE)) /* neither defined */
1556
1631
ND_width(n) = ND_height(n) = DEF_POINT;
1633
ND_width(n) = ND_height(n) = w;
1635
sz = ND_width(n)*POINTS_PER_INCH;
1636
peripheries = late_int(n, N_peripheries, peripheries, 0);
1637
if (peripheries < 1) outp = 1;
1638
else outp = peripheries;
1640
vertices = N_NEW(outp * sides, pointf);
1641
P.y = P.x = sz / 2.;
1642
vertices[0].x = -P.x;
1643
vertices[0].y = -P.y;
1645
if (peripheries > 1) {
1646
for (j = 1, i = 2; j < peripheries; j++) {
1649
vertices[i].x = -P.x;
1650
vertices[i].y = -P.y;
1652
vertices[i].x = P.x;
1653
vertices[i].y = P.y;
1659
poly->peripheries = peripheries;
1661
poly->orientation = 0;
1663
poly->distortion = 0;
1664
poly->vertices = vertices;
1666
ND_height(n) = ND_width(n) = PS2INCH(sz);
1667
ND_shape_info(n) = (void *) poly;
1671
point_inside(inside_t* inside_context, pointf p)
1673
static node_t *lastn; /* last node argument */
1674
static double radius;
1676
node_t *n = inside_context->s.n;
1678
P = ccwrotatepf(p, 90*GD_rankdir(n->graph));
1682
polygon_t *poly = (polygon_t *) ND_shape_info(n);
1684
/* index to outer-periphery */
1685
outp = 2*(poly->peripheries - 1);
1686
if (outp < 0) outp = 0;
1688
radius = poly->vertices[outp+1].x;
1692
/* inside bounding box? */
1693
if ((fabs(P.x) > radius) || (fabs(P.y) > radius))
1696
return (hypot(P.x, P.y) <= radius);
1699
static void point_gencode(GVJ_t * job, node_t * n)
1701
obj_state_t *obj = job->obj;
1703
int i, j, sides, peripheries, style;
1704
pointf P, *vertices;
1709
int doMap = (obj->url || obj->explicit_tooltip);
1711
if (doMap && !(job->flags & EMIT_CLUSTERS_LAST))
1712
gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
1714
poly = (polygon_t *) ND_shape_info(n);
1715
vertices = poly->vertices;
1716
sides = poly->sides;
1717
peripheries = poly->peripheries;
1718
if (A_size < sides) {
1720
AF = ALLOC(A_size, AF, pointf);
1723
checkStyle(n, &style);
1724
if (style & INVISIBLE)
1725
gvrender_set_style(job, point_style);
1727
gvrender_set_style(job, &point_style[1]);
1729
if (ND_gui_state(n) & GUI_STATE_ACTIVE) {
1730
color = late_nnstring(n, N_activepencolor, DEFAULT_ACTIVEPENCOLOR);
1731
gvrender_set_pencolor(job, color);
1732
color = late_nnstring(n, N_activefillcolor, DEFAULT_ACTIVEFILLCOLOR);
1733
gvrender_set_fillcolor(job, color);
1735
else if (ND_gui_state(n) & GUI_STATE_SELECTED) {
1736
color = late_nnstring(n, N_selectedpencolor, DEFAULT_SELECTEDPENCOLOR);
1737
gvrender_set_pencolor(job, color);
1738
color = late_nnstring(n, N_selectedfillcolor, DEFAULT_SELECTEDFILLCOLOR);
1739
gvrender_set_fillcolor(job, color);
1741
else if (ND_gui_state(n) & GUI_STATE_DELETED) {
1742
color = late_nnstring(n, N_deletedpencolor, DEFAULT_DELETEDPENCOLOR);
1743
gvrender_set_pencolor(job, color);
1744
color = late_nnstring(n, N_deletedfillcolor, DEFAULT_DELETEDFILLCOLOR);
1745
gvrender_set_fillcolor(job, color);
1747
else if (ND_gui_state(n) & GUI_STATE_VISITED) {
1748
color = late_nnstring(n, N_visitedpencolor, DEFAULT_VISITEDPENCOLOR);
1749
gvrender_set_pencolor(job, color);
1750
color = late_nnstring(n, N_visitedfillcolor, DEFAULT_VISITEDFILLCOLOR);
1751
gvrender_set_fillcolor(job, color);
1754
color = findFillDflt (n, "black");
1755
gvrender_set_fillcolor(job, color); /* emit fill color */
1756
pencolor(job, n); /* emit pen color */
1760
/* if no boundary but filled, set boundary color to fill color */
1761
if (peripheries == 0) {
1764
gvrender_set_pencolor(job, color);
1767
for (j = 0; j < peripheries; j++) {
1768
for (i = 0; i < sides; i++) {
1769
P = vertices[i + j * sides];
1770
AF[i].x = P.x + (double)ND_coord_i(n).x;
1771
AF[i].y = P.y + (double)ND_coord_i(n).y;
1773
gvrender_ellipse(job, AF, sides, filled);
1774
/* fill innermost periphery only */
1779
if (job->flags & EMIT_CLUSTERS_LAST)
1780
gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
1781
gvrender_end_anchor(job);
1562
1785
/* the "record" shape is a rudimentary table formatter */