]> granicus.if.org Git - graphviz/commitdiff
Fix multicolor parsing to handle floating point round-off problems.
authorEmden Gansner <erg@research.att.com>
Thu, 9 Aug 2012 19:07:18 +0000 (15:07 -0400)
committerEmden Gansner <erg@research.att.com>
Thu, 9 Aug 2012 19:07:18 +0000 (15:07 -0400)
lib/common/emit.c

index 25d21b63a5d6c11bb5d238a763356a67282552af..11e2de9f8b343257dea08ca42382e168fce86175 100644 (file)
@@ -380,6 +380,9 @@ static double getSegLen (char* s)
     return -1;
 }
 
+#define EPS 1E-5
+#define AEQ0(x) (((x) < EPS) && ((x) > -EPS))
+
 /* parseSegs:
  * Parse string of form color;float:color;float:...:color;float:color
  * where the floats are optional, nonnegative, sum to <= 1.
@@ -420,8 +423,9 @@ parseSegs (char* clrs, int nseg, colorsegs_t** psegs)
     segs->segs = s = N_NEW(nseg+1,colorseg_t);
     for (color = strtok(colors, ":"); color; color = strtok(0, ":")) {
        if ((v = getSegLen (color)) >= 0) {
-           if (v > left) {
-               if (doWarn && ((v-left) > 0.00001)) {
+           double del = v - left;
+           if (del > 0) {
+               if (doWarn && !AEQ0(del)) {
                    agerr (AGWARN, "Total size > 1 in \"%s\" color spec ", clrs);
                    doWarn = 0;
                    rval = 3;
@@ -442,6 +446,10 @@ parseSegs (char* clrs, int nseg, colorsegs_t** psegs)
            freeSegs (segs);
            return rval;
        }
+       if (AEQ0(left)) {
+           left = 0;
+           break;
+       }
     }
 
     /* distribute remaining into slot with t == 0; if none, add to last */
@@ -2069,7 +2077,7 @@ static int multicolor (GVJ_t * job, edge_t * e, char** styles, char* colors, int
        bz = ED_spl(e)->list[i];
        first = 1;
        for (s = segs->segs; s->color; s++) {
-           if (s->t == 0) continue;
+           if (AEQ0(s->t)) continue;
            gvrender_set_pencolor(job, s->color);
            sum += s->t;
            if (first) {
@@ -2077,20 +2085,24 @@ static int multicolor (GVJ_t * job, edge_t * e, char** styles, char* colors, int
                splitBSpline (&bz, sum, &bz_l, &bz_r);
                gvrender_beziercurve(job, bz_l.list, bz_l.size, FALSE, FALSE, FALSE);
                free (bz_l.list);
-               if (sum == 1) free (bz_r.list);
+               if (AEQ0(sum-1)) {
+                   free (bz_r.list);
+                   break;
+               }
            }
-           else if (sum < 1.0) {
+           else if (AEQ0(sum-1)) {
+               endcolor = s->color;
+               gvrender_beziercurve(job, bz_r.list, bz_r.size, FALSE, FALSE, FALSE);
+               free (bz_r.list);
+               break;
+           }
+           else {
                bz0 = bz_r;
                splitBSpline (&bz0, sum, &bz_l, &bz_r);
                free (bz0.list);
                gvrender_beziercurve(job, bz_l.list, bz_l.size, FALSE, FALSE, FALSE);
                free (bz_l.list);
            }
-           else {
-               endcolor = s->color;
-               gvrender_beziercurve(job, bz_r.list, bz_r.size, FALSE, FALSE, FALSE);
-               free (bz_r.list);
-           }
                
        }
                 /* arrow_gen resets the job style  (How?  FIXME)