fix: harden array builder editing workflows

This commit is contained in:
2026-08-28 23:10:41 +09:00
parent 3714146df9
commit 122b6cf7be
14 changed files with 1148 additions and 165 deletions
+41
View File
@@ -86,6 +86,47 @@ test("Array canvas hit test는 반경 안의 가장 가까운 마이크와 채
assertEqual(hitTestMicrophone({ x: 0, y: 0 }, arrayDefinition.microphones, viewport, 2), null, "miss");
});
test("Array canvas hit test는 viewport 변환에서 overflow된 마이크를 건너뛴다", () => {
const viewport = {
plot: { x: 0, y: 0 },
xMin: 0,
yMax: 100,
scale: 2,
};
const microphones = [
{ id: "overflow", position: [Number.MAX_VALUE, 0, 0] },
{ id: "normal", position: [5, 5, 0] },
];
assertEqual(
arrayPositionToCanvas(microphones[0].position, viewport).x,
Infinity,
"fixture overflows after viewport conversion",
);
assertEqual(
hitTestMicrophone({ x: 10, y: 190 }, microphones, viewport, 2)?.id,
"normal",
"finite microphone remains hittable",
);
});
test("Array canvas fit은 극단적인 유한 좌표에서도 aperture fallback viewport를 유지한다", () => {
const arrayDefinition = fixture();
arrayDefinition.microphones[0].position = [-Number.MAX_VALUE, 0, 0];
arrayDefinition.microphones[1].position = [Number.MAX_VALUE, 0, 0];
const viewport = fitArrayViewport(800, 420, arrayDefinition);
for (const [name, value] of Object.entries({
scale: viewport.scale,
metersPerPixel: viewport.metersPerPixel,
xMin: viewport.xMin,
xMax: viewport.xMax,
yMin: viewport.yMin,
yMax: viewport.yMax,
})) {
assert(Number.isFinite(value), name + " remains finite");
}
assert(viewport.xMin < 0 && viewport.xMax > 0, "fallback keeps the aperture around the origin");
});
test("Array canvas grid와 keyboard nudge의 순수 helper가 1/2/5 및 y-up 규칙을 따른다", () => {
const candidates = [niceGridStep(0.008), niceGridStep(0.08), niceGridStep(0.8), niceGridStep(8)];
for (const step of candidates) {