float discCovered(float dist, float rad) { // proportion of unit disc covered by a second disc of radius rad placed // dist from centre of first disc. // // WLOG, the second disc is displaced horizontally to the right. // xl = rightwards distance to intersection of the two circles. // xs = normalised leftwards distance from centre of second disc to intersection. // d = vertical distance to an intersection point // The clampings handle the cases where one disc contains the other. const float radsq = rad*rad; const float xl = Clamp((dist*dist + 1.f - radsq) / (2.f*std::max(0.001f,dist)), -1.f, 1.f); const float xs = Clamp((dist - xl)/std::max(0.001f,rad), -1.f, 1.f); const float d = sqrt(std::max(0.f, 1.f - xl*xl)); const float th = Clamp(acosf(xl), 0.f, float(M_PI)); const float th2 = Clamp(acosf(xs), 0.f, float(M_PI)); assert(!is_nan(d) && !is_nan(th) && !is_nan(th2)); // covered area can be calculated as the sum of segments from the two // discs plus/minus some triangles, and it works out as follows: return Clamp((th + radsq*th2 - dist*d)/float(M_PI), 0.f, 1.f); }