plotEllipseRectWidth function

void plotEllipseRectWidth(
  1. double x0,
  2. double y0,
  3. double x1,
  4. double y1,
  5. double th,
  6. SetPixel setPixel,
)

Implementation

void plotEllipseRectWidth(double x0, double y0, double x1, double y1, double th, SetPixel setPixel) {
  /* draw anti-aliased ellipse inside rectangle with thick line */
  double a = (x1 - x0).abs();
  final double b = (y1 - y0).abs();
  int b1 = b.floor() & 1; /* outer diameter */
  double a2 = a - 2 * th;
  double b2 = b - 2 * th; /* inner diameter */
  double dx = 4 * (a - 1) * b * b;
  double dy = 4 * (b1 - 1) * a * a; /* error increment */
  double i = a + b2;
  double err = b1 * a * a;
  double dx2;
  double dy2;
  double e2;
  double ed;
  /* thick line correction */
  if (th < 1.5) {
    return plotEllipseRectAA(x0, y0, x1, y1, setPixel);
  }
  if ((th - 1) * (2 * b - th) > a * a) {
    b2 = math.sqrt(a * (b - a) * i * a2) / (a - th);
  }
  if ((th - 1) * (2 * a - th) > b * b) {
    a2 = math.sqrt(b * (a - b) * i * b2) / (b - th);
    th = (a - a2) / 2;
  }
  if (a == 0 || b == 0) {
    return plotLine(x0, y0, x1, y1, setPixel);
  }
  if (x0 > x1) {
    x0 = x1;
    x1 += a;
  } /* if called with swapped points */
  if (y0 > y1) {
    y0 = y1; /* .. exchange them */
  }
  if (b2 <= 0) {
    th = a; /* filled ellipse */
  }
  e2 = th - th.floor();
  th = x0 + th - e2;
  dx2 = 4 * (a2 + 2 * e2 - 1) * b2 * b2;
  dy2 = 4 * (b1 - 1) * a2 * a2;
  e2 = dx2 * e2;
  y0 += (b.floor() + 1) >> 1;
  y1 = y0 - b1; /* starting pixel */
  a = 8 * a * a;
  b1 = 8 * b.floor() * b.floor();
  a2 = 8 * a2 * a2;
  b2 = 8 * b2 * b2;

  do {
    for (;;) {
      if (err < 0 || x0 > x1) {
        i = x0;
        break;
      }
      i = math.min(dx, dy);
      ed = math.max(dx, dy);
      if (y0 == y1 + 1 && 2 * err > dx && a > b1) {
        ed = a / 4; /* x-tip */
      } else {
        ed += 2 * ed * i * i / (4 * ed * ed + i * i + 1) + 1; /* approx ed=sqrt(dx*dx+dy*dy) */
      }

      i = 255 * err / ed; /* outside anti-aliasing */
      setPixel(x0, y0, i.round());
      setPixel(x0, y1, i.round());
      setPixel(x1, y0, i.round());
      setPixel(x1, y1, i.round());
      if (err + dy + a < dx) {
        i = x0 + 1;
        break;
      }
      x0++;
      x1--;
      err -= dx;
      dx -= b1; /* x error increment */
    }
    for (; i < th && 2 * i <= x0 + x1; i++) {
      /* fill line pixel */
      setPixel(i, y0);
      setPixel(x0 + x1 - i, y0);
      setPixel(i, y1);
      setPixel(x0 + x1 - i, y1);
    }
    while (e2 > 0 && x0 + x1 >= 2 * th) {
      /* inside anti-aliasing */
      i = math.min(dx2, dy2);
      ed = math.max(dx2, dy2);
      if (y0 == y1 + 1 && 2 * e2 > dx2 && a2 > b2) {
        ed = a2 / 4; /* x-tip */
      } else {
        ed += 2 * ed * i * i / (4 * ed * ed + i * i); /* approximation */
      }
      i = 255 - 255 * e2 / ed; /* get intensity value by pixel error */
      setPixel(th, y0, i.round());
      setPixel(x0 + x1 - th, y0, i.round());
      setPixel(th, y1, i.round());
      setPixel(x0 + x1 - th, y1, i.round());
      if (e2 + dy2 + a2 < dx2) {
        break;
      }
      th++;
      e2 -= dx2;
      dx2 -= b2; /* x error increment */
    }
    e2 += dy2 += a2;
    y0++;
    y1--;
    err += dy += a; /* y step */
  } while (x0 < x1);

  if (y0 - y1 <= b) {
    if (err > dy + a) {
      y0--;
      y1++;
      err -= dy -= a;
    }
    for (; y0 - y1 <= b; err += dy += a) {
      /* too early stop of flat ellipses */
      i = 255 * 4 * err / b1; /* -> finish tip of ellipse */
      setPixel(x0, y0, i.round());
      setPixel(x1, y0++, i.round());
      setPixel(x0, y1, i.round());
      setPixel(x1, y1--, i.round());
    }
  }
}