orbit/js/scan/ScanGeometry.js

44 lines
1.6 KiB
JavaScript

// Pure circle-circle geometry for the DEEP SCAN pulse (js/scan/ScanPulse.js).
// No Phaser — kept separately so it is unit-testable in Node
// (dev/scan.test.mjs).
//
// The wavefront is a ship-centered circle of radius r. Only the part inside
// the tether region (the UNION of tether circles) is drawn — outside the
// union the wave is absorbed, so the pulse stops at the union boundary.
// For one tether circle (center A, radius R) vs the origin circle (center
// O, radius r), both "windows" are the classic circle-circle intersection:
/**
* The arc of a circle of radius `a` (around its center) that lies inside a
* circle of radius `b`, the two centers `d` apart.
*
* Returns the half-angle (radians) of the window, centered on the
* `a`-center → `b`-center direction:
* Math.PI — the whole circle `a` is inside `b`
* -1 — no overlap
*/
export function arcInCircle(a, b, d) {
if (a <= 0) return -1;
if (d === 0) return a <= b ? Math.PI : -1;
const c = (a * a + d * d - b * b) / (2 * a * d);
if (c <= -1) return Math.PI;
if (c >= 1) return -1;
return Math.acos(c);
}
/**
* The wavefront radius at which an origin-centered front first touches a
* tether of radius `R` whose anchor is `d` away (0 = concentric circles —
* the front grows through the whole rim at once, at r = R).
*/
export function contactRadius(R, d) {
if (d === 0) return R;
return Math.abs(R - d);
}
/** The farthest point of a tether rim from the origin — the point the wave
* is absorbed last. The sweep runs to the max of this over all tethers. */
export function farRadius(R, d) {
return R + d;
}