Fix: reject invalid inverse lens-map weights

Check spherical area weight sums against a fixed 1e-8 tolerance and normalize accepted weights before interpolation. Skip invalid images in both catalog paths.

Add a thin-triangle regression for both parities, document the measured tolerance margin, and refresh HDR fixtures with strict comparisons restored.
This commit is contained in:
wyj committed 2026-09-06 17:47:09 -04:00
1 parent 8741597d9d
commit 265d7b95d5
6 files changed
+72 -5

No files matched your search

+44
View File
@@ -330,6 +330,50 @@ int main(void) {
goto done;
}
frame_lens_mesh_destroy(&fine_mesh);
/* Schwarzschild level-4/J=0.2 ring triangle: the old edge tolerance accepts
* (1,0,0) although it is outside, producing unsigned weights summing to
* 1.09608. Keep a genuine interior source after it to check that rejecting
* one source does not discard subsequent stars. Exercise both parities. */
const double thin_directions[3][3] = {
{0.99999998891116071, 0.00013431364716360775, 6.4323579270168807e-05},
{0.99999997228355786, -0.00021216644782556991, -0.00010206998544149922},
{0.9999927016945267, -0.0034455730513416835, -0.001650631403158936}};
LensVertex thin_vertices[3] = {
{.image_x = 40, .image_y = 40, .status = RAY_ENDPOINT_ESCAPED},
{.image_x = 48, .image_y = 40, .status = RAY_ENDPOINT_ESCAPED},
{.image_x = 40, .image_y = 48, .status = RAY_ENDPOINT_ESCAPED}};
LensTriangle thin_triangle = {.vertex = {0, 1, 2}};
FrameLensMesh thin_mesh = {.vertices = thin_vertices, .vertex_count = 3,
.triangles = &thin_triangle, .triangle_count = 1};
Star thin_stars[2] = {
{.direction = {1, 0, 0}, .temperature_K = 7000, .amplitude = 1},
{.temperature_K = 7000, .amplitude = 1}};
for (int i = 0; i < 3; ++i) {
memcpy(thin_vertices[i].n_infinity, thin_directions[i],
sizeof thin_directions[i]);
memcpy(thin_vertices[i].camera_direction, thin_directions[i],
sizeof thin_directions[i]);
for (int axis = 0; axis < 3; ++axis)
thin_stars[1].direction[axis] += thin_directions[i][axis];
}
const double thin_norm = hypot(hypot(thin_stars[1].direction[0],
thin_stars[1].direction[1]),
thin_stars[1].direction[2]);
for (int axis = 0; axis < 3; ++axis)
thin_stars[1].direction[axis] /= thin_norm;
StarCatalog thin_catalog = {.stars = thin_stars, .count = 2};
for (int parity = 0; parity < 2; ++parity) {
thin_triangle.vertex[1] = parity ? 2 : 1;
thin_triangle.vertex[2] = parity ? 1 : 2;
memset(hdr, 0, (size_t)width * height * 3 * sizeof *hdr);
if (frame_splat_catalog(&thin_mesh, &thin_catalog, hdr, width, height,
test_exposure, &psf, NULL, 1.0, 1.0,
psf_relative_tail, 0.0, 0, 1, NULL, NULL, NULL) != 1 ||
hdr[3 * (43 * width + 43)] <= 0.0) {
fputs("thin source-triangle inverse-map regression failed\n", stderr);
goto done;
}
}
/* Refinement probes are temporary until their generation is complete. A
* shared diagonal probe must produce one stable midpoint and conforming
* children only after its endpoint has been installed. */