1/*
2float fOpUnionRound(float a, float b, float r) {
3    vec2 u = max(vec2(r - a,r - b), vec2(0));
4    return max(r, min (a, b)) - length(u);
5}
6
7float fOpIntersectionRound(float a, float b, float r) {
8    vec2 u = max(vec2(r + a,r + b), vec2(0));
9    return min(-r, max (a, b)) + length(u);
10}
11*/
12
13round_min2(k,a,b) = max(k, min(a,b)) - mag(max([k-a,k-b], 0));
14round_union2 k (s1, s2) = make_shape {
15    dist p : round_min2(k, s1.dist p, s2.dist p),
16    colour p : (
17        var d1 := s1.dist p;
18        var d2 := s2.dist p;
19        if (d2 <= 0 || d2 <= d1) s2.colour p else s1.colour p
20    ),
21    bbox : [min(s1.bbox'0, s2.bbox'0), max(s1.bbox'1, s2.bbox'1)],
22    is_2d : s1.is_2d && s2.is_2d,
23    is_3d : s1.is_3d && s2.is_3d,
24};
25
26round_min3(k,a,b,c) = max(k, min(a,b,c)) - mag(max([k-a,k-b,k-c], 0));
27round_union3 k (s1, s2, s3) = make_shape {
28    dist p : round_min3(k, s1.dist p, s2.dist p, s3.dist p),
29/*
30    colour p : (
31        var d1 := s1.dist p;
32        var d2 := s2.dist p;
33        if (d2 <= 0 || d2 <= d1) s2.colour p else s1.colour p
34    ),
35*/
36    bbox : [min(s1.bbox'0, s2.bbox'0), max(s1.bbox'1, s2.bbox'1)],
37    is_2d : s1.is_2d && s2.is_2d,
38    is_3d : s1.is_3d && s2.is_3d,
39};
40
41/* bad gradient
42round_union2 .5 (
43    rect.exact(.1,3),
44    rect.exact(3,.1) >> rotate(45*deg),
45)
46*/
47
48/* it works
49round_union3 1.184 (
50    circle 1 >> move(cis(90*deg)),
51    circle 1 >> move(cis(-30*deg)),
52    circle 1 >> move(cis(-150*deg)),
53)
54*/
55
56union (
57    round_union2 1 (
58        square 1,
59        square 1,
60    ),
61    square 1 >> colour black,
62    square .25 >> colour red >> move(.625,0),
63)
64