d47135580518b138a64b785eddbc65891e48be21
kate
  Fri Jan 12 10:13:52 2018 -0800
Integrate antialiased ellipse code.  Awaits antialiasing fix from Braney. refs #17512

diff --git src/hg/lib/hvGfx.c src/hg/lib/hvGfx.c
index 392e1d2..1ac59e9 100644
--- src/hg/lib/hvGfx.c
+++ src/hg/lib/hvGfx.c
@@ -253,66 +253,30 @@
 struct memPng *png = (struct memPng *)hvg->vg->data;
 struct memGfx *img = (struct memGfx *)png;
 if ((x < img->clipMinX) || (x > img->clipMaxX) || (y < img->clipMinY) || (y > img->clipMaxY))
     return;
 
 Color *pt = _mgPixAdr(img,x,y);
 float invFrac = 1 - frac;
 
 int r = COLOR_32_RED(*pt) * invFrac + COLOR_32_RED(col) * frac;
 int g = COLOR_32_GREEN(*pt) * invFrac + COLOR_32_GREEN(col) * frac;
 int b = COLOR_32_BLUE(*pt) * invFrac + COLOR_32_BLUE(col) * frac;
 hvGfxDot(hvg, x, y, MAKECOLOR_32(r,g,b));
 hvGfxDot(hvg, x, y, MAKECOLOR_32(r,g,b));
 }
 
-void hvGfxCurveSeg(struct hvGfx *hvg, int x0, int y0, int x1, int y1, int x2, int y2, Color color)
-/* Draw a segment of a curve within 3 points (quadratic Bezier)
- * Adapted trivially from code posted on github and at http://members.chello.at/~easyfilter/bresenham.html */
- /* Thanks to author  * @author Zingl Alois
- * @date 22.08.2016 */
-{
-  int sx = x2-x1, sy = y2-y1;
-  long xx = x0-x1, yy = y0-y1, xy;              /* relative values for checks */
-  double dx, dy, err, cur = xx*sy-yy*sx;                         /* curvature */
-
-  assert(xx*sx <= 0 && yy*sy <= 0);       /* sign of gradient must not change */
-
-  if (sx*(long)sx+sy*(long)sy > xx*xx+yy*yy) {      /* begin with longer part */
-    x2 = x0; x0 = sx+x1; y2 = y0; y0 = sy+y1; cur = -cur;       /* swap P0 P2 */
-  }
-  if (cur != 0) {                                         /* no straight line */
-    xx += sx; xx *= sx = x0 < x2 ? 1 : -1;                /* x step direction */
-    yy += sy; yy *= sy = y0 < y2 ? 1 : -1;                /* y step direction */
-    xy = 2*xx*yy; xx *= xx; yy *= yy;               /* differences 2nd degree */
-    if (cur*sx*sy < 0) {                                /* negated curvature? */
-      xx = -xx; yy = -yy; xy = -xy; cur = -cur;
-    }
-    dx = 4.0*sy*cur*(x1-x0)+xx-xy;                  /* differences 1st degree */
-    dy = 4.0*sx*cur*(y0-y1)+yy-xy;
-    xx += xx; yy += yy; err = dx+dy+xy;                     /* error 1st step */
-    do {
-      hvGfxDot(hvg, x0, y0, color);                                          /* plot curve */
-      if (x0 == x2 && y0 == y2) return;       /* last pixel -> curve finished */
-      y1 = 2*err < dx;                       /* save value for test of y step */
-      if (2*err > dy) { x0 += sx; dx -= xy; err += dy += yy; }      /* x step */
-      if (    y1    ) { y0 += sy; dy -= xy; err += dx += xx; }      /* y step */
-    } while (dy < 0 && dx > 0);        /* gradient negates -> algorithm fails */
-  }
-  hvGfxLine(hvg, x0,y0, x2,y2, color);                       /* plot remaining part to end */
-}
-
 void hvGfxCurveSegAA(struct hvGfx *hvg, int x0, int y0, int x1, int y1, int x2, int y2, Color color)
 /* Draw a segment of an anti-aliased curve within 3 points (quadratic Bezier)
  * Adapted trivially from code posted on github and at http://members.chello.at/~easyfilter/bresenham.html */
  /* Thanks to author  * @author Zingl Alois
  * @date 22.08.2016 */
 {
    int sx = x2-x1, sy = y2-y1;
    long xx = x0-x1, yy = y0-y1, xy;             /* relative values for checks */
    double dx, dy, err, ed, cur = xx*sy-yy*sx;                    /* curvature */
 
    assert(xx*sx <= 0 && yy*sy <= 0);      /* sign of gradient must not change */
 
    if (sx*(long)sx+sy*(long)sy > xx*xx+yy*yy) {     /* begin with longer part */
       x2 = x0; x0 = sx+x1; y2 = y0; y0 = sy+y1; cur = -cur;     /* swap P0 P2 */
    }
@@ -369,89 +333,114 @@
       x0 = x1 = x; y0 = y; y1 = floor(r+0.5);             /* P0 = P4, P1 = P8 */
    }
    if ((long)(y0-y1)*(y2-y1) > 0) {                    /* vertical cut at P6? */
       t = y0-2*y1+y2; t = (y0-y1)/t;
       r = (1-t)*((1-t)*x0+2.0*t*x1)+t*t*x2;                       /* Bx(t=P6) */
       t = (y0*y2-y1*y1)*t/(y0-y1);                       /* gradient dP6/dy=0 */
       x = floor(r+0.5); y = floor(t+0.5);
       r = (x1-x0)*(t-y0)/(y1-y0)+x0;                  /* intersect P6 | P0 P1 */
       hvGfxCurveSegAA(hvg,x0,y0, floor(r+0.5),y, x,y, color);
       r = (x1-x2)*(t-y2)/(y1-y2)+x2;                  /* intersect P7 | P1 P2 */
       x0 = x; x1 = floor(r+0.5); y0 = y1 = y;             /* P0 = P6, P1 = P7 */
    }
    hvGfxCurveSegAA(hvg,x0,y0, x1,y1, x2,y2, color);                  /* remaining part */
 }
 
-#ifdef PROBLEM
+void hvGfxEllipseDrawAA(struct hvGfx *hvg, int x0, int y0, int x1, int y1, Color color, int mode)
 // TODO: Tame anti-aliasing with Braney help, or drop
-void hvGfxEllipseAA(struct hvGfx *hvg, int x0, int y0, int x1, int y1, Color color)
-/* Draw an anti-aliased ellipse specified by rectangle, using Bresenham algorithm.
+/* Draw an anti-aliased ellipse or half (top or bottom) using Bresenham algorithm.
  * Point 0 is left, point 1 is top of rectangle
  * Adapted trivially from code posted at http://members.chello.at/~easyfilter/bresenham.html
  */
 {
    long a = abs(x1-x0), b = abs(y1-y0), b1 = b&1;                 /* diameter */
    float dx = 4*(a-1.0)*b*b, dy = 4*(b1+1)*a*a;            /* error increment */
    float ed, i, err = b1*a*a-dx+dy;                        /* error of 1.step */
    bool f;
 
    if (a == 0 || b == 0) return hvGfxLine(hvg, x0, y0, x1, y1, color);
    if (x0 > x1) { x0 = x1; x1 += a; }        /* if called with swapped points */
    if (y0 > y1) y0 = y1;                                  /* .. exchange them */
    y0 += (b+1)/2; y1 = y0-b1;                               /* starting pixel */
    a = 8*a*a; b1 = 8*b*b;
 
-   int q = 0;
-   for (q=0; q<1000; q++) {                             /* approximate ed=sqrt(dx*dx+dy*dy) */
+   // FIXME: end condition not triggered on this loop
    //for (;;) {                             /* approximate ed=sqrt(dx*dx+dy*dy) */
+   int q = 0;
+   for (q=0; q<10000; q++) {                             /* approximate ed=sqrt(dx*dx+dy*dy) */
+   //
       i = min(dx,dy); ed = max(dx,dy);
       if (y0 == y1+1 && err > dy && a > b1) ed = 255*4./a;           /* x-tip */
       else ed = 255/(ed+2*ed*i*i/(4*ed*ed+i*i));             /* approximation */
       i = ed*fabs(err+dx-dy);           /* get intensity value by pixel error */
-      mixDot(hvg, x0,y0, i, color); mixDot(hvg, x0,y1, i, color);
-      mixDot(hvg, x1,y0, i, color); mixDot(hvg, x1,y1, i, color);
+      if (mode == ELLIPSE_BOTTOM || mode == ELLIPSE_FULL) {
+          mixDot(hvg, x0,y0, i, color); 
+          mixDot(hvg, x1,y0, i, color); 
+      }
+      if (mode == ELLIPSE_TOP || mode == ELLIPSE_FULL) {
+          mixDot(hvg, x0,y1, i, color);
+          mixDot(hvg, x1,y1, i, color);
+      }
 
       //mixDot(hvg, x0,y0, 1-fabs(err-dx-dy-xy)/ed, color);          /* plot curve */
 
       if ((f = 2*err+dy) >= 0) {                  /* x step, remember condition */
          if (x0 >= x1) break;
          i = ed*(err+dx);
          if (i < 255) {
-            mixDot(hvg, x0,y0+1, i, color); mixDot(hvg, x0,y1-1, i, color);
-            mixDot(hvg, x1,y0+1, i, color); mixDot(hvg, x1,y1-1, i, color);
+             if (mode == ELLIPSE_BOTTOM || mode == ELLIPSE_FULL) {
+                 mixDot(hvg, x0,y0+1, i, color); 
+                 mixDot(hvg, x1,y0+1, i, color); 
+             }
+             if (mode == ELLIPSE_TOP || mode == ELLIPSE_FULL) {
+                 mixDot(hvg, x0,y1-1, i, color);
+                 mixDot(hvg, x1,y1-1, i, color);
+             }
          }          /* do error increment later since values are still needed */
       }
       if ((2*err) <= dx) {                                            /* y step */
          i = ed*(dy-err);
          if (i < 255) {
-            mixDot(hvg, x0+1,y0, i, color); mixDot(hvg, x1-1,y0, i, color);
-            mixDot(hvg, x0+1,y1, i, color); mixDot(hvg, x1-1,y1, i, color);
+             if (mode == ELLIPSE_BOTTOM || mode == ELLIPSE_FULL) {
+                 mixDot(hvg, x0+1,y0, i, color); 
+                 mixDot(hvg, x1-1,y0, i, color); 
+             }
+             if (mode == ELLIPSE_TOP || mode == ELLIPSE_FULL) {
+                 mixDot(hvg, x0+1,y1, i, color);
+                 mixDot(hvg, x1-1,y1, i, color);
+             }
          }
          y0++; y1--; err += dy += a;
       }
       if (f) { x0++; x1--; err -= dx -= b1; }            /* x error increment */
    }
    if (--x0 == x1++)                       /* too early stop of flat ellipses */
       while (y0-y1 < b) {
          i = 255*4*fabs(err+dx)/b1;               /* -> finish tip of ellipse */
-         mixDot(hvg, x0,++y0, i, color); mixDot(hvg, x1,y0, i, color);
-         mixDot(hvg, x0,--y1, i, color); mixDot(hvg, x1,y1, i, color);
+         if (mode == ELLIPSE_BOTTOM || mode == ELLIPSE_FULL) {
+             mixDot(hvg, x0,y0+1, i, color); 
+             mixDot(hvg, x1,y0+1, i, color); 
+         }
+         if (mode == ELLIPSE_TOP || mode == ELLIPSE_FULL) {
+             mixDot(hvg, x0,y1-1, i, color);
+             mixDot(hvg, x1,y1-1, i, color);
+         }
+         y0++; y1--;
          err += dy += a;
       }
 }
 
-#endif
 
 void hvGfxEllipseDraw(struct hvGfx *hvg, int x0, int y0, int x1, int y1, Color color, int mode)
 /* Draw an ellipse (or limit to top or bottom) specified by rectangle, using Bresenham algorithm.
  * Point 0 is left, point 1 is top of rectangle
  * Adapted trivially from code posted at http://members.chello.at/~easyfilter/bresenham.html
  */
 {
    int a = abs(x1-x0), b = abs(y1-y0), b1 = b&1; /* values of diameter */
    long dx = 4*(1-a)*b*b, dy = 4*(b1+1)*a*a; /* error increment */
    long err = dx+dy+b1*a*a, e2; /* error of 1.step */
 
    if (x0 > x1) { x0 = x1; x1 += a; } /* if called with swapped points */
    if (y0 > y1) y0 = y1; /* .. exchange them */
    y0 += (b+1)/2; y1 = y0-b1;   /* starting pixel */
    a *= 8*a; b1 = 8*b*b;