~ubuntu-branches/ubuntu/lucid/graphviz/lucid-updates

« back to all changes in this revision

Viewing changes to lib/common/shapes.c

  • Committer: Bazaar Package Importer
  • Author(s): Bryce Harrington
  • Date: 2008-06-19 20:23:23 UTC
  • mfrom: (1.2.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20080619202323-ls23h96ntj9ny94m
Tags: 2.18-1ubuntu1
* Merge from debian unstable, remaining changes:
  - Build depend on liblualib50-dev instead of liblua5.1-0-dev.
  - Drop libttf-dev (libttf-dev is in universe) (LP: #174749).
  - Replace gs-common with ghostscript.
  - Build-depend on python-dev instead of python2.4-dev or python2.5-dev.
  - Mention the correct python version for the python bindings in the
    package description.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: shapes.c,v 1.81 2007/11/05 21:33:36 erg Exp $ $Revision: 1.81 $ */
 
1
/* $id: shapes.c,v 1.82 2007/12/24 04:50:36 ellson Exp $ $Revision: 1.97 $ */
2
2
/* vim:set shiftwidth=4 ts=8: */
3
3
 
4
4
/**********************************************************
24
24
static port Center = { {0, 0}, -1, 0, 0, 0, 1, 0, 0 };
25
25
 
26
26
#define ATTR_SET(a,n) ((a) && (*(agxget(n,a->index)) != '\0'))
 
27
  /* Default point size = 0.05 inches or 3.6 points */
27
28
#define DEF_POINT 0.05
 
29
  /* Minimum point size = 0.0003 inches or 0.02 points
 
30
   * This will make the radius 0.01 points, which is the smallest
 
31
   * non-zero number output by gvprintnum in gvdevice.c
 
32
   */
 
33
#define MIN_POINT 0.0003
28
34
  /* extra null character needed to avoid style emitter from thinking
29
35
   * there are arguments.
30
36
   */
31
37
static char *point_style[3] = { "invis\0", "filled\0", 0 };
32
 
static shape_desc *point_desc;
33
38
 
34
39
/* forward declarations of functions used in shapes tables */
35
40
 
48
53
static void record_gencode(GVJ_t * job, node_t * n);
49
54
 
50
55
static void point_init(node_t * n);
 
56
static void point_gencode(GVJ_t * job, node_t * n);
 
57
static boolean point_inside(inside_t * inside_context, pointf p);
51
58
 
52
59
static boolean epsf_inside(inside_t * inside_context, pointf p);
53
60
static void epsf_gencode(GVJ_t * job, node_t * n);
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 };
79
87
 
94
102
 
95
103
/* True if style requires processing through node_round_corners. */
96
104
#define SPECIAL_CORNERS(style) \
97
 
        ((style) & (ROUNDED | DIAGONALS | DOGEAR | TAB | BOX3D | COMPONENT))
 
105
        ((style) & (ROUNDED | DIAGONALS | DOGEAR | TAB | FOLDER | BOX3D | COMPONENT))
98
106
 
99
107
/*
100
108
 * every shape has these functions:
133
141
    point_init,
134
142
    poly_free,
135
143
    poly_port,
136
 
    poly_inside,
 
144
    point_inside,
137
145
    NULL,
138
 
    poly_gencode
 
146
    point_gencode
139
147
};
140
148
static shape_functions record_fns = {
141
149
    record_init,
175
183
    {"octagon", &poly_fns, &p_octagon},
176
184
    {"note", &poly_fns, &p_note},
177
185
    {"tab", &poly_fns, &p_tab},
 
186
    {"folder", &poly_fns, &p_folder},
178
187
    {"box3d", &poly_fns, &p_box3d},
179
188
    {"component", &poly_fns, &p_component},
180
189
    {"rect", &poly_fns, &p_box},
249
258
}
250
259
 
251
260
static
252
 
char *findFill(node_t * n)
 
261
char *findFillDflt(node_t * n, char* dflt)
253
262
{
254
263
    char *color;
255
264
 
258
267
        /* for backward compatibilty, default fill is same as pen */
259
268
        color = late_nnstring(n, N_color, "");
260
269
        if (!color[0]) {
261
 
            if (ND_shape(n) == point_desc) {
262
 
                color = "black";
263
 
            }
264
270
#ifdef WITH_CODEGENS
265
 
            else if (Output_lang == MIF) color = "black";
 
271
            if (Output_lang == MIF) color = "black";
 
272
            else
266
273
#endif
267
 
            else color = DEFAULT_FILL;
 
274
            color = dflt;
268
275
        }
269
276
    }
270
277
    return color;
271
278
}
272
279
 
 
280
static
 
281
char *findFill (node_t * n)
 
282
{
 
283
    return (findFillDflt (n, DEFAULT_FILL));
 
284
}
 
285
 
273
286
static char **checkStyle(node_t * n, int *flagp)
274
287
{
275
288
    char *style;
317
330
 
318
331
static int stylenode(GVJ_t * job, node_t * n)
319
332
{
320
 
    char **pstyle;
321
 
    int istyle;
 
333
    char **pstyle, *s;
 
334
    int istyle, penwidth;
322
335
 
323
336
    if ((pstyle = checkStyle(n, &istyle)))
324
337
        gvrender_set_style(job, pstyle);
 
338
 
 
339
    if (N_penwidth && ((s=agxget(n, N_penwidth->index)) && s[0])) {
 
340
        penwidth = late_double(n, N_penwidth, 1.0, 0.0);
 
341
        gvrender_set_penwidth(job, penwidth);
 
342
    }
 
343
 
325
344
    return istyle;
326
345
}
327
346
 
362
381
 
363
382
    if (style & DIAGONALS)
364
383
        mode = DIAGONALS;
365
 
    else if (style & (DOGEAR | TAB | BOX3D | COMPONENT))
366
 
        mode = style & (DOGEAR | TAB | BOX3D | COMPONENT);
 
384
    else if (style & (DOGEAR | TAB | FOLDER | BOX3D | COMPONENT))
 
385
        mode = style & (DOGEAR | TAB | FOLDER | BOX3D | COMPONENT);
367
386
    else
368
387
        mode = ROUNDED;
369
388
    B = N_NEW(4 * sides + 4, pointf);
463
482
        gvrender_polyline(job, C, 2);
464
483
        break;
465
484
    case TAB:
 
485
      /*
 
486
       * Adjust the perimeter for the protrusions.
 
487
       *
 
488
       *  D[3] +--+ D[2]
 
489
       *       |  |          B[1]
 
490
       *  B[3] +  +----------+--+ AF[0]=B[0]=D[0]
 
491
       *       |  B[2]=D[1]     |
 
492
       *  B[4] +                |
 
493
       *       |                |
 
494
       *  B[5] +                |
 
495
       *       +----------------+
 
496
       *
 
497
       */
466
498
        gvrender_set_pencolor(job, penc);
467
499
        if (style & FILLED)
468
500
            gvrender_set_fillcolor(job, fillc); /* emit fill color */
484
516
        C[0] = B[3];
485
517
        C[1] = B[2];
486
518
        gvrender_polyline(job, C, 2);
 
519
      break;
 
520
    case FOLDER:
 
521
      /*
 
522
       * Adjust the perimeter for the protrusions.
 
523
       *
 
524
       *            D[2] +----+ D[1]
 
525
       *  B[3]=         /      \
 
526
       *  D[4] +--+----+     +  + AF[0]=B[0]=D[0]
 
527
       *       |  B[2] D[3] B[1]|
 
528
       *  B[4] +                |
 
529
       *       |                |
 
530
       *  B[5] +                |
 
531
       *       +----------------+
 
532
       *
 
533
       */
 
534
      gvrender_set_pencolor(job, penc);
 
535
      if (style & FILLED)
 
536
          gvrender_set_fillcolor(job, fillc); /* emit fill color */
 
537
      /* Add the folder edges. */
 
538
      D = N_NEW(sides + 3, pointf);
 
539
      D[0] = AF[0];
 
540
      D[1].x = AF[0].x - (AF[0].x - B[1].x) / 4;
 
541
      D[1].y = AF[0].y + (B[3].y - B[4].y) / 3;
 
542
      D[2].x = AF[0].x - 2 * (AF[0].x - B[1].x);
 
543
      D[2].y = D[1].y;
 
544
      D[3].x = AF[0].x - 2.25 * (AF[0].x - B[1].x);
 
545
      D[3].y = B[3].y;
 
546
      D[4].x = B[3].x;
 
547
      D[4].y = B[3].y;
 
548
      for (seg = 4; seg < sides + 3; seg++)
 
549
          D[seg] = AF[seg - 3];
 
550
      gvrender_polygon(job, D, sides + 3, style & FILLED);
 
551
      free(D);
487
552
        break;
488
553
    case BOX3D:
489
554
        assert(sides == 4);
626
691
 
627
692
static void poly_init(node_t * n)
628
693
{
629
 
    pointf dimen, bb;
 
694
    pointf dimen, min_bb, bb;
630
695
    point imagesize;
631
696
    pointf P, Q, R;
632
697
    pointf *vertices;
633
698
    char *p, *sfile;
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;
640
 
    int i, j, outp;
 
705
    int i, j, outp, labelloc;
641
706
    polygon_t *poly = NEW(polygon_t);
642
707
 
643
708
    regular = ND_shape(n)->polygon->regular;
698
763
        } else
699
764
            PAD(dimen);
700
765
    }
 
766
    /* quantization */
 
767
    if ((temp = GD_drawing(n->graph)->quantum) > 0.0) {
 
768
        temp = POINTS(temp);
 
769
        dimen.x = quant(dimen.x, temp);
 
770
        dimen.y = quant(dimen.y, temp);
 
771
    }
701
772
 
702
773
    imagesize.x = imagesize.y = 0;
703
774
    if (ND_shape(n)->usershape) {
716
787
            }
717
788
            else {
718
789
                GD_has_images(n->graph) = TRUE;
 
790
                imagesize.x += 2; /* some fixed padding */
 
791
                imagesize.y += 2;
719
792
            }
720
793
        }
721
794
    }
729
802
        }
730
803
        else {
731
804
            GD_has_images(n->graph) = TRUE;
 
805
            imagesize.x += 2; /* some fixed padding */
 
806
            imagesize.y += 2;
732
807
        }
733
808
    }
734
 
    if (mapbool(late_string(n, N_fixed, "false"))) {
735
 
        if ((width < dimen.x) || (height < dimen.y))
736
 
            agerr(AGWARN,
737
 
                  "node '%s', graph '%s' size too small for label\n",
738
 
                  n->name, n->graph->name);
739
 
        dimen.x = dimen.y = 0;
740
 
    }
741
 
    else {
742
 
        dimen.x = MAX(dimen.x, imagesize.x+2);
743
 
        dimen.y = MAX(dimen.y, imagesize.y+2);
744
 
    }
745
 
 
746
 
    /* quantization */
747
 
    if ((temp = GD_drawing(n->graph)->quantum) > 0.0) {
748
 
        temp = POINTS(temp);
749
 
        dimen.x = quant(dimen.x, temp);
750
 
        dimen.y = quant(dimen.y, temp);
751
 
    }
752
 
 
753
 
    /* If regular, make label dimensions the same.
754
 
     * Need this to guarantee final node size is regular.
755
 
     */
756
 
    if (regular) {
757
 
        dimen.x = dimen.y = MAX(dimen.x, dimen.y);
758
 
    }
 
809
 
 
810
    /* initialize node bb to labelsize */
 
811
    bb.x = MAX(dimen.x, imagesize.x);
 
812
    bb.y = MAX(dimen.y, imagesize.y);
759
813
 
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 */
763
817
        sides = 120;
764
818
    }
765
819
 
766
 
    /* add extra padding to allow for the shape */
767
 
    if (sides <= 2) {
768
 
        /* for ellipses, add padding based on the smaller radii */
769
 
        if (dimen.y > dimen.x)
770
 
            temp = dimen.x * (sqrt(2.) - 1.);
771
 
        else
772
 
            temp = dimen.y * (sqrt(2.) - 1.);
773
 
        dimen.x += temp;
774
 
        dimen.y += temp;
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')
 
823
        labelloc = +1;
 
824
    else if (p && p[0] == 'b')
 
825
        labelloc = -1;
 
826
    else
 
827
        labelloc = 0;
 
828
 
 
829
    if (sides == 4 && (ROUND(orientation) % 90) == 0
776
830
               && distortion == 0. && skew == 0.) {
777
831
        /* for regular boxes the fit should be exact */
778
832
    } else {
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);
782
 
        dimen.x /= temp;
783
 
        dimen.y /= temp;
784
 
        /* add padding based on the smaller radii */
785
 
        if (dimen.y > dimen.x)
786
 
            temp = dimen.x * (sqrt(2.) - 1.);
787
 
        else
788
 
            temp = dimen.y * (sqrt(2.) - 1.);
789
 
        dimen.x += temp;
790
 
        dimen.y += temp;
 
835
        temp = bb.y * SQRT2;
 
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)));
 
839
            bb.y = height;
 
840
        }
 
841
        else {
 
842
            bb.x *= SQRT2;
 
843
            bb.y = temp;
 
844
        }
 
845
#if 0
 
846
        if (sides > 2) {
 
847
            temp = cos(M_PI / sides);
 
848
            bb.x /= temp;
 
849
            bb.y /= temp;
 
850
            /* FIXME - for odd-sided polygons, e.g. triangles, there
 
851
            would be a better fit with some vertical adjustment of the shape */
 
852
        }
 
853
#endif
791
854
    }
792
855
 
 
856
    /* at this point, bb is the minimum size of node that can hold the label */
 
857
    min_bb = bb;
 
858
 
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);
796
 
 
797
 
    /* adjust text justification */
 
860
    if (mapbool(late_string(n, N_fixed, "false"))) {
 
861
        if ((width < bb.x) || (height < bb.y))
 
862
            agerr(AGWARN,
 
863
                  "node '%s', graph '%s' size too small for label\n",
 
864
                  n->name, n->graph->name);
 
865
        bb.x = width;
 
866
        bb.y = height;
 
867
    }
 
868
    else {
 
869
        bb.x = width = MAX(width, bb.x);
 
870
        bb.y = height = MAX(height, bb.y);
 
871
    }
 
872
 
 
873
    /* If regular, make dimensions the same.
 
874
     * Need this to guarantee final node size is regular.
 
875
     */
 
876
    if (regular) {
 
877
        bb.x = bb.y = MAX(bb.x, bb.y);
 
878
    }
 
879
 
 
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;
 
885
        if (temp > 0) 
 
886
            ND_label(n)->d.x = temp;
 
887
    }
 
888
 
 
889
    /* adjust text vertical location */
 
890
    temp = bb.y - min_bb.y;
 
891
    if (dimen.y < imagesize.y)
 
892
        temp += imagesize.y - dimen.y;
 
893
    if (temp > 0) {
 
894
        if (labelloc < 0)
 
895
            ND_label(n)->d.y = -temp;
 
896
        else if (labelloc > 0)
 
897
            ND_label(n)->d.y = temp;
 
898
        else
 
899
            ND_label(n)->d.y = 0;
801
900
    }
802
901
 
803
902
    outp = peripheries;
827
926
        }
828
927
    } else {
829
928
        vertices = N_NEW(outp * sides, pointf);
830
 
        sectorangle = 2. * PI / sides;
 
929
        sectorangle = 2. * M_PI / sides;
831
930
        sidelength = sin(sectorangle / 2.);
832
931
        skewdist = hypot(fabs(distortion) + fabs(skew), 1.);
833
 
        gdistortion = distortion * sqrt(2.) / cos(sectorangle / 2.);
 
932
        gdistortion = distortion * SQRT2 / cos(sectorangle / 2.);
834
933
        gskew = skew / 2.;
835
 
        angle = (sectorangle - PI) / 2.;
 
934
        angle = (sectorangle - M_PI) / 2.;
836
935
        sincos(angle, &sinx, &cosx);
837
936
        R.x = .5 * cosx;
838
937
        R.y = .5 * sinx;
839
938
        xmax = ymax = 0.;
840
 
        angle += (PI - sectorangle) / 2.;
 
939
        angle += (M_PI - sectorangle) / 2.;
841
940
        for (i = 0; i < sides; i++) {
842
941
 
843
942
            /*next regular vertex */
896
995
                R = vertices[(i + 1) % sides];
897
996
                alpha = beta;
898
997
                beta = atan2(R.y - Q.y, R.x - Q.x);
899
 
                gamma = (alpha + PI - beta) / 2.;
 
998
                gamma = (alpha + M_PI - beta) / 2.;
900
999
 
901
1000
                /*find distance along bisector to */
902
1001
                /*intersection of next periphery */
903
1002
                temp = GAP / sin(gamma);
904
1003
 
905
1004
                /*convert this distance to x and y */
906
 
                delta = alpha - gamma;
907
 
                sincos(delta, &sinx, &cosx);
 
1005
                sincos((alpha - gamma), &sinx, &cosx);
908
1006
                sinx *= temp;
909
1007
                cosx *= temp;
910
1008
 
1121
1219
        angle *= -1; 
1122
1220
        break;
1123
1221
    case RANKDIR_LR:
1124
 
        angle -= PI * 0.5;
 
1222
        angle -= M_PI * 0.5;
1125
1223
        break;
1126
1224
    case RANKDIR_RL:
1127
 
        if (angle == PI)
1128
 
            angle = -0.5 * PI;
1129
 
        else if (angle == PI * 0.75)
1130
 
            angle = -0.25 * PI;
1131
 
        else if (angle == PI * 0.5)
 
1225
        if (angle == M_PI)
 
1226
            angle = -0.5 * M_PI;
 
1227
        else if (angle == M_PI * 0.75)
 
1228
            angle = -0.25 * M_PI;
 
1229
        else if (angle == M_PI * 0.5)
1132
1230
            angle = 0;
1133
 
        else if (angle == PI * 0.25)
 
1231
        else if (angle == M_PI * 0.25)
1134
1232
            angle = angle;
1135
1233
        else if (angle == 0)
1136
 
            angle = PI * 0.5;
1137
 
        else if (angle == PI * -0.25)
1138
 
            angle = PI * 0.75;
1139
 
        else if (angle == PI * -0.5)
1140
 
            angle = PI;
1141
 
        else if (angle == PI * -0.75)
 
1234
            angle = M_PI * 0.5;
 
1235
        else if (angle == M_PI * -0.25)
 
1236
            angle = M_PI * 0.75;
 
1237
        else if (angle == M_PI * -0.5)
 
1238
            angle = M_PI;
 
1239
        else if (angle == M_PI * -0.75)
1142
1240
            angle = angle;
1143
1241
        break;
1144
1242
    }
1238
1336
            clip = FALSE;
1239
1337
            switch (*compass) {
1240
1338
            case '\0':
1241
 
                theta = -PI * 0.5;
 
1339
                theta = -M_PI * 0.5;
1242
1340
                defined = TRUE;
1243
1341
                side = sides & BOTTOM;
1244
1342
                break;
1245
1343
            case 'e':
1246
 
                theta = -PI * 0.25;
 
1344
                theta = -M_PI * 0.25;
1247
1345
                defined = TRUE;
1248
1346
                if (ictxt) p = compassPoint (ictxt, -INT_MAX, INT_MAX);
1249
1347
                else p.x = b.UR.x;
1250
1348
                side = sides & (BOTTOM | RIGHT);
1251
1349
                break;
1252
1350
            case 'w':
1253
 
                theta = -PI * 0.75;
 
1351
                theta = -M_PI * 0.75;
1254
1352
                defined = TRUE;
1255
1353
                if (ictxt) p = compassPoint (ictxt, -INT_MAX, -INT_MAX);
1256
1354
                else p.x = b.LL.x;
1266
1364
            break;
1267
1365
        case 'w':
1268
1366
            p.x = b.LL.x;
1269
 
            theta = PI;
 
1367
            theta = M_PI;
1270
1368
            constrain = TRUE;
1271
1369
            defined = TRUE;
1272
1370
            clip = FALSE;
1279
1377
            switch (*compass) {
1280
1378
            case '\0':
1281
1379
                defined = TRUE;
1282
 
                theta = PI * 0.5;
 
1380
                theta = M_PI * 0.5;
1283
1381
                side = sides & TOP;
1284
1382
                break;
1285
1383
            case 'e':
1286
1384
                defined = TRUE;
1287
 
                theta = PI * 0.25;
 
1385
                theta = M_PI * 0.25;
1288
1386
                if (ictxt) p = compassPoint (ictxt, INT_MAX, INT_MAX);
1289
1387
                else p.x = b.UR.x;
1290
1388
                side = sides & (TOP | RIGHT);
1291
1389
                break;
1292
1390
            case 'w':
1293
1391
                defined = TRUE;
1294
 
                theta = PI * 0.75;
 
1392
                theta = M_PI * 0.75;
1295
1393
                if (ictxt) p = compassPoint (ictxt, INT_MAX, -INT_MAX);
1296
1394
                else p.x = b.LL.x;
1297
1395
                side = sides & (TOP | LEFT);
1318
1416
        pp->order = MC_SCALE/2;
1319
1417
    else {
1320
1418
        /* compute angle with 0 at north pole, increasing CCW */
1321
 
        double angle = atan2(p.y,p.x) + 1.5*PI;
1322
 
        if (angle >= 2*PI) angle -= 2*PI;
1323
 
        pp->order = (int)((MC_SCALE * angle) / (2*PI));
 
1419
        double angle = atan2(p.y,p.x) + 1.5*M_PI;
 
1420
        if (angle >= 2*M_PI) angle -= 2*M_PI;
 
1421
        pp->order = (int)((MC_SCALE * angle) / (2*M_PI));
1324
1422
    }
1325
1423
    pp->constrained = constrain;
1326
1424
    pp->defined = defined;
1394
1492
    xsize = (double)(ND_lw_i(n) + ND_rw_i(n)) / POINTS(ND_width(n));
1395
1493
    ysize = (double)ND_ht_i(n) / POINTS(ND_height(n));
1396
1494
 
1397
 
    if (ND_shape(n) == point_desc) {
1398
 
        checkStyle(n, &style);
1399
 
        if (style & INVISIBLE)
1400
 
            gvrender_set_style(job, point_style);
1401
 
        else
1402
 
            gvrender_set_style(job, &point_style[1]);
1403
 
        style = FILLED;
1404
 
    } else {
1405
 
        style = stylenode(job, n);
1406
 
    }
 
1495
    style = stylenode(job, n);
 
1496
 
1407
1497
    if (ND_gui_state(n) & GUI_STATE_ACTIVE) {
1408
1498
        color = late_nnstring(n, N_activepencolor, DEFAULT_ACTIVEPENCOLOR);
1409
1499
        gvrender_set_pencolor(job, color);
1522
1612
 */
1523
1613
static void point_init(node_t * n)
1524
1614
{
1525
 
    textlabel_t *p;
1526
 
 
1527
 
    if (!point_desc) {
1528
 
        shape_desc *ptr;
1529
 
        for (ptr = Shapes; ptr->name; ptr++)
1530
 
            if (streq(ptr->name, "point")) {
1531
 
                point_desc = ptr;
1532
 
                break;
1533
 
            }
1534
 
        assert(point_desc);
1535
 
    }
1536
 
 
1537
 
    /* adjust label to "" */
1538
 
    p = ND_label(n);
1539
 
    free_label(p);
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;
 
1617
    double sz;
 
1618
    pointf P, *vertices;
 
1619
    int i, j;
 
1620
    double w, h;
1542
1621
 
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
1547
1626
     */
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));
1551
 
        } else
1552
 
            ND_height(n) = ND_width(n);
1553
 
    } else if (ATTR_SET(N_height, n)) {
1554
 
        ND_width(n) = ND_height(n);
1555
 
    } else
 
1627
    w = late_double(n, N_width, MAXDOUBLE, MIN_POINT);
 
1628
    h = late_double(n, N_height, MAXDOUBLE, MIN_POINT);
 
1629
    w = MIN(w,h);
 
1630
    if ((w == MAXDOUBLE) && (h == MAXDOUBLE)) /* neither defined */
1556
1631
        ND_width(n) = ND_height(n) = DEF_POINT;
1557
 
 
1558
 
    poly_init(n);
1559
 
}
1560
 
 
 
1632
    else
 
1633
        ND_width(n) = ND_height(n) = w;
 
1634
 
 
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;
 
1639
    sides = 2;
 
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;
 
1644
    vertices[1] = P;
 
1645
    if (peripheries > 1) {
 
1646
        for (j = 1, i = 2; j < peripheries; j++) {
 
1647
            P.x += GAP;
 
1648
            P.y += GAP;
 
1649
            vertices[i].x = -P.x;
 
1650
            vertices[i].y = -P.y;
 
1651
            i++;
 
1652
            vertices[i].x = P.x;
 
1653
            vertices[i].y = P.y;
 
1654
            i++;
 
1655
        }
 
1656
        sz = 2. * P.x;
 
1657
    }
 
1658
    poly->regular = 1;
 
1659
    poly->peripheries = peripheries;
 
1660
    poly->sides = 2;
 
1661
    poly->orientation = 0;
 
1662
    poly->skew = 0;
 
1663
    poly->distortion = 0;
 
1664
    poly->vertices = vertices;
 
1665
 
 
1666
    ND_height(n) = ND_width(n) = PS2INCH(sz);
 
1667
    ND_shape_info(n) = (void *) poly;
 
1668
}
 
1669
 
 
1670
static boolean 
 
1671
point_inside(inside_t* inside_context, pointf p)
 
1672
{
 
1673
    static node_t *lastn;       /* last node argument */
 
1674
    static double radius;
 
1675
    pointf P;
 
1676
    node_t *n = inside_context->s.n;
 
1677
 
 
1678
    P = ccwrotatepf(p, 90*GD_rankdir(n->graph));
 
1679
 
 
1680
    if (n != lastn) {
 
1681
        int outp;
 
1682
        polygon_t *poly = (polygon_t *) ND_shape_info(n);
 
1683
 
 
1684
        /* index to outer-periphery */
 
1685
        outp = 2*(poly->peripheries - 1);
 
1686
        if (outp < 0) outp = 0;
 
1687
 
 
1688
        radius = poly->vertices[outp+1].x;
 
1689
        lastn = n;
 
1690
    }
 
1691
 
 
1692
    /* inside bounding box? */
 
1693
    if ((fabs(P.x) > radius) || (fabs(P.y) > radius))
 
1694
        return FALSE;
 
1695
 
 
1696
    return (hypot(P.x, P.y) <= radius);
 
1697
}
 
1698
 
 
1699
static void point_gencode(GVJ_t * job, node_t * n)
 
1700
{
 
1701
    obj_state_t *obj = job->obj;
 
1702
    polygon_t *poly;
 
1703
    int i, j, sides, peripheries, style;
 
1704
    pointf P, *vertices;
 
1705
    static pointf *AF;
 
1706
    static int A_size;
 
1707
    boolean filled;
 
1708
    char *color;
 
1709
    int doMap = (obj->url || obj->explicit_tooltip);
 
1710
 
 
1711
    if (doMap && !(job->flags & EMIT_CLUSTERS_LAST))
 
1712
        gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
 
1713
 
 
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) {
 
1719
        A_size = sides + 2;
 
1720
        AF = ALLOC(A_size, AF, pointf);
 
1721
    }
 
1722
 
 
1723
    checkStyle(n, &style);
 
1724
    if (style & INVISIBLE)
 
1725
        gvrender_set_style(job, point_style);
 
1726
    else
 
1727
        gvrender_set_style(job, &point_style[1]);
 
1728
 
 
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);
 
1734
    }
 
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);
 
1740
    }
 
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);
 
1746
    }
 
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);
 
1752
    }
 
1753
    else {
 
1754
        color = findFillDflt (n, "black");
 
1755
        gvrender_set_fillcolor(job, color); /* emit fill color */
 
1756
        pencolor(job, n);       /* emit pen color */
 
1757
    }
 
1758
    filled = TRUE;
 
1759
 
 
1760
    /* if no boundary but filled, set boundary color to fill color */
 
1761
    if (peripheries == 0) {
 
1762
        peripheries = 1;
 
1763
        if (color[0])
 
1764
            gvrender_set_pencolor(job, color);
 
1765
    }
 
1766
 
 
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;
 
1772
        }
 
1773
        gvrender_ellipse(job, AF, sides, filled);
 
1774
        /* fill innermost periphery only */
 
1775
        filled = FALSE;
 
1776
    }
 
1777
 
 
1778
    if (doMap) {
 
1779
        if (job->flags & EMIT_CLUSTERS_LAST)
 
1780
            gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
 
1781
        gvrender_end_anchor(job);
 
1782
    }
 
1783
}
1561
1784
 
1562
1785
/* the "record" shape is a rudimentary table formatter */
1563
1786
 
1878
2101
    char *textbuf;              /* temp buffer for storing labels */
1879
2102
    int sides = BOTTOM | RIGHT | TOP | LEFT; 
1880
2103
 
1881
 
    if (Nop)
1882
 
        flip = NOT(GD_realflip(n->graph));
1883
 
    else
1884
 
        flip = NOT(GD_flip(n->graph));
 
2104
    /* Always use rankdir to determine how records are laid out */
 
2105
    flip = NOT(GD_realflip(n->graph));
1885
2106
    reclblp = ND_label(n)->text;
1886
2107
    len = strlen(reclblp);
1887
2108
    textbuf = N_NEW(len + 1, char);