Total circles area: Difference between revisions
Content added Content deleted
(Used INFINITY as in the second C entry, for uniformity + tags) |
(Small changes in second C entry: C99, VLAs, less commas, 4 spaces indented, variables scope narrowing) |
||
Line 169: | Line 169: | ||
#include <math.h> |
#include <math.h> |
||
#include <stdlib.h> |
#include <stdlib.h> |
||
#include <stdbool.h> |
|||
typedef double |
typedef double Fp; |
||
typedef struct { |
typedef struct { Fp x, y, r, r2, y0, y1; } Circle; |
||
circle circles[] = { |
|||
{ 1.6417233788, 1.6121789534, 0.0848270516},... |
|||
/* data snipped for space, copy from previous example */ |
|||
}; |
|||
Circle circles[] = { |
|||
inline F min(F a, F b) { return a < b ? a : b; } |
|||
{ 1.6417233788, 1.6121789534, 0.0848270516}, |
|||
inline F max(F a, F b) { return a > b ? a : b; } |
|||
// ... data snipped for space, copy from previous example. |
|||
inline F sq(F x) { return x * x; } |
|||
{ 0.0152957411, 0.0638919221, 0.9771215985}}; |
|||
inline F dist(F x, F y, F x1, F y1) { return sqrt(sq(x - x1) + sq(y - y1)); } |
|||
inline Fp min(Fp a, Fp b) { return a < b ? a : b; } |
|||
typedef struct { F x0, x1; } sect_t; |
|||
inline Fp max(Fp a, Fp b) { return a > b ? a : b; } |
|||
F spans(circle *c, int n_circs, F ymin, F step, F ymax) |
|||
inline Fp square(Fp x) { return x * x; } |
|||
{ |
|||
F y, total = 0; |
|||
int i, j, n, row = 1 + ceil((ymax - ymin) / step); |
|||
inline Fp dist(const Fp x0, const Fp y0, const Fp x1, const Fp y1) { |
|||
sect_t *sect = malloc(n_circs * sizeof(sect_t)); |
|||
return sqrt(square(x0 - x1) + square(y0 - y1)); |
|||
inline void swap_s(int i, int j) { |
|||
} |
|||
sect_t ss; |
|||
ss = sect[i], sect[i] = sect[j], sect[j] = ss; |
|||
} |
|||
typedef struct { Fp x0, x1; } Sect; |
|||
inline void swap_c(int i, int j) { |
|||
circle cc; |
|||
cc = c[i], c[i] = c[j], c[j] = cc; |
|||
} |
|||
Fp spans(Circle *c, size_t n_circles, |
|||
for (i = 0; i < n_circs; i++) |
|||
const Fp ymin, const Fp step, const Fp ymax) { |
|||
for (j = i + 1; j < n_circs; j++) |
|||
// Safe if n_circles is not very large. |
|||
if (c[i].y1 < c[j].y1) swap_c(i, j); |
|||
Sect sects[n_circles]; |
|||
Fp total = 0; |
|||
while (row--) { |
|||
y = ymin + step * row; // could probably do "y -= step"; not sure |
|||
// GNU C99 extension. |
|||
for (n = n_circs, i = 0; i < n; ) { |
|||
inline void swap_s(const int i, const int j) { |
|||
if (y >= c[i].y1) n = i; |
|||
const Sect ss = sects[i]; |
|||
else if (y <= c[i].y0) { |
|||
sects[i] = sects[j]; |
|||
circle cc = c[i]; |
|||
sects[j] = ss; |
|||
} |
|||
c[--n_circs] = cc; |
|||
--n; |
|||
} else { |
|||
F dx = sqrt(c[i].r2 - sq(y - c[i].y)); |
|||
sect[i].x0 = c[i].x - dx; |
|||
sect[i].x1 = c[i].x + dx; |
|||
i++; |
|||
} |
|||
} |
|||
inline void swap_c(const int i, const int j) { |
|||
if (!n) continue; |
|||
const Circle cc = c[i]; |
|||
c[i] = c[j]; |
|||
c[j] = cc; |
|||
} |
|||
for (size_t i = 0; i < n_circles; i++) |
|||
for (size_t j = i + 1; j < n_circles; j++) |
|||
int swapped = 0; |
|||
if (c[i].y1 < c[j].y1) |
|||
swap_c(i, j); |
|||
if (sect[j].x0 > sect[j+1].x0) { |
|||
swap_s(j, j + 1); |
|||
swap_c(j, j + 1); |
|||
swapped = 1; |
|||
} |
|||
if (!swapped) break; |
|||
} |
|||
for (int row = 1 + ceil((ymax - ymin) / step); row; row--) { |
|||
sect_t *cur = sect; |
|||
// Could probably do "y -= step", not sure. |
|||
total += cur->x1 - cur->x0; |
|||
const Fp y = ymin + step * row; |
|||
for (i = 1; i < n; i++) { |
|||
if (sect[i].x1 <= cur->x1) continue; |
|||
total += sect[i].x1 - max(sect[i].x0, cur->x1); |
|||
cur = sect + i; |
|||
} |
|||
} |
|||
free(sect); |
|||
return total; |
|||
} |
|||
size_t n = n_circles; |
|||
int main(void) |
|||
for (size_t i = 0; i < n; ) { |
|||
{ |
|||
if (y >= c[i].y1) |
|||
int i, n_circs = sizeof(circles) / sizeof(circle); |
|||
n = i; |
|||
else if (y <= c[i].y0) { |
|||
const Circle cc = c[i]; |
|||
for (size_t j = i + 1; j < n_circles; j++) |
|||
c[j - 1] = c[j]; |
|||
n_circles--; |
|||
c[n_circles] = cc; |
|||
n--; |
|||
} else { |
|||
const Fp dx = sqrt(c[i].r2 - square(y - c[i].y)); |
|||
sects[i].x0 = c[i].x - dx; |
|||
sects[i].x1 = c[i].x + dx; |
|||
i++; |
|||
} |
|||
} |
|||
if (!n) |
|||
continue; |
|||
for (size_t i = n; i--; ) { // Bubble sort. Important. |
|||
bool swapped = false; |
|||
for (size_t j = 0; j < i; j++) |
|||
if (sects[j].x0 > sects[j + 1].x0) { |
|||
swap_s(j, j + 1); |
|||
swap_c(j, j + 1); |
|||
swapped = true; |
|||
} |
|||
if (!swapped) |
|||
break; |
|||
} |
|||
Sect *cur = sects; |
|||
total += cur->x1 - cur->x0; |
|||
for (size_t i = 1; i < n; i++) { |
|||
if (sects[i].x1 <= cur->x1) |
|||
continue; |
|||
total += sects[i].x1 - max(sects[i].x0, cur->x1); |
|||
cur = sects + i; |
|||
} |
|||
} |
|||
return total; |
|||
} |
|||
int main() { |
|||
F miny = INFINITY, maxy = -INFINITY; |
|||
size_t n_circles = sizeof(circles) / sizeof(Circle); |
|||
for (i = 0; i < n_circs; i++) { |
|||
circles[i].r2 = sq(circles[i].r); |
|||
circles[i].y0 = circles[i].y - circles[i].r; |
|||
circles[i].y1 = circles[i].y + circles[i].r; |
|||
miny = min(circles[i].y0, miny); |
|||
maxy = max(circles[i].y1, maxy); |
|||
} |
|||
// Remove fully covered circles. |
|||
circle *c1, *c2; |
|||
for (Circle *c1 = circles + n_circles; c1-- > circles; ) |
|||
for (Circle *c2 = circles + n_circles; c2-- > circles; ) |
|||
// Remove c1 if it's inside c2. Helps, not important. |
|||
if (c1 != c2 && |
|||
dist(c1->x, c1->y, c2->x, c2->y) + c1->r <= c2->r) { |
|||
*c1 = circles[--n_circs]; |
|||
n_circles--; |
|||
break; |
|||
*c1 = circles[n_circles]; |
|||
} |
|||
break; |
|||
} |
|||
Fp miny = INFINITY, maxy = -INFINITY; |
|||
int s = 1 << 20; // Definitely overkill. Definitely. |
|||
for (size_t i = 0; i < n_circles; i++) { |
|||
circles[i].r2 = square(circles[i].r); |
|||
circles[i].y0 = circles[i].y - circles[i].r; |
|||
circles[i].y1 = circles[i].y + circles[i].r; |
|||
miny = min(miny, circles[i].y0); |
|||
maxy = max(maxy, circles[i].y1); |
|||
} |
|||
const size_t s = 1U << 20; // Definitely overkill. Definitely. |
|||
printf("area = %.10f at\t%d scanlines\n", |
|||
const Fp sp = spans(circles, n_circles, |
|||
spans(circles, n_circs, floor(miny * s) / s, 1./s, maxy) / s, |
|||
floor(miny * s) / s, 1.0 / s, maxy); |
|||
printf("Area = %.10f at\t%d scanlines.\n", |
|||
sp / s, (int)((maxy - floor(miny * s) / s) * s)); |
|||
return 0; |
|||
}</lang> |
}</lang> |
||
{{out}} |
{{out}} |