plotEllipseRectWidth function
void
plotEllipseRectWidth()
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());
}
}
}