Frame: gate fold refinement by Jacobian

This commit is contained in:
wyj committed 2026-08-29 01:17:47 -04:00
1 parent 4c575fa8b5
commit b95c6579bd
4 files changed
+65 -31

No files matched your search

+37 -12
View File
@@ -344,9 +344,11 @@ static double spherical_signed_area(const double a[3], const double b[3],
}
/* Returns whether the discrete source/image solid-angle ratio is available.
* Captured and degenerate image triangles have no reliable value. */
* A zero output parity is a valid, critical (zero-Jacobian) result; captured
* and degenerate image triangles have no reliable parity. */
static int discrete_jacobian(const FrameLensMesh *mesh,
const LensTriangle *triangle, double *value) {
const LensTriangle *triangle, double *value,
signed char *parity) {
const LensVertex *a = &mesh->vertices[triangle->vertex[0]];
const LensVertex *b = &mesh->vertices[triangle->vertex[1]];
const LensVertex *c = &mesh->vertices[triangle->vertex[2]];
@@ -363,6 +365,7 @@ static int discrete_jacobian(const FrameLensMesh *mesh,
if (!isfinite(jacobian))
return 0;
*value = jacobian;
*parity = jacobian > 0.0 ? 1 : jacobian < 0.0 ? -1 : 0;
return 1;
}
@@ -456,8 +459,11 @@ int frame_lens_mesh_finish_generation(FrameLensMesh *mesh,
MeshEdge *edges = calloc(edge_count, sizeof *edges);
unsigned char *requested = calloc(edge_count, sizeof *requested);
unsigned char *allowed = calloc(mesh->triangle_count, sizeof *allowed);
if (edges == NULL || requested == NULL || allowed == NULL) {
free(edges); free(requested); free(allowed);
signed char *parity = calloc(mesh->triangle_count, sizeof *parity);
double *jacobians = calloc(mesh->triangle_count, sizeof *jacobians);
if (edges == NULL || requested == NULL || allowed == NULL || parity == NULL ||
jacobians == NULL) {
free(edges); free(requested); free(allowed); free(parity); free(jacobians);
return -1;
}
for (size_t i = 0; i < mesh->triangle_count; ++i) {
@@ -472,13 +478,32 @@ int frame_lens_mesh_finish_generation(FrameLensMesh *mesh,
if (allowed[i]) {
const unsigned int side = longest_side(mesh, triangle);
requested[3 * i + side] = probe_requires_split(mesh, triangle, side, config);
double jacobian;
if (discrete_jacobian(mesh, triangle, &jacobian) &&
fabs(jacobian) < config->jacobian_minimum)
requested[3 * i + side] = 1;
(void)discrete_jacobian(mesh, triangle, &jacobians[i], &parity[i]);
}
}
qsort(edges, edge_count, sizeof *edges, compare_mesh_edge);
/* A fold is selected only when its adjacent discrete parities disagree and
* at least one of those leaves is close enough to the critical curve. */
for (size_t first = 0; first < edge_count;) {
size_t last = first + 1;
while (last < edge_count && edges[last].a == edges[first].a &&
edges[last].b == edges[first].b)
++last;
if (last - first == 2) {
const size_t left = edges[first].triangle;
const size_t right = edges[first + 1].triangle;
if (parity[left] != 0 && parity[right] != 0 &&
parity[left] != parity[right] &&
fmin(fabs(jacobians[left]), fabs(jacobians[right])) <
config->jacobian_minimum) {
if (allowed[left] && allowed[right]) {
requested[3 * left + edges[first].side] = 1;
requested[3 * right + edges[first + 1].side] = 1;
}
}
}
first = last;
}
/* A requested interior edge is split by both incident leaves, preserving a
* conforming mesh. If either side has reached its geometric limit, reject
* the whole edge instead of introducing a T-junction. */
@@ -542,7 +567,7 @@ int frame_lens_mesh_finish_generation(FrameLensMesh *mesh,
if (split_edges == 0) {
mesh->sample_count = 0;
mesh->samples_include_probes = 0;
free(edges); free(requested); free(allowed);
free(edges); free(requested); free(allowed); free(parity); free(jacobians);
return 0;
}
/* Allocate a single stable midpoint vertex for each requested edge group. */
@@ -559,7 +584,7 @@ int frame_lens_mesh_finish_generation(FrameLensMesh *mesh,
first = last;
}
if (ensure_vertices(mesh, mesh->vertex_count + midpoint_count)) {
free(edges); free(requested); free(allowed);
free(edges); free(requested); free(allowed); free(parity); free(jacobians);
return -1;
}
size_t next_vertex = mesh->vertex_count;
@@ -586,7 +611,7 @@ int frame_lens_mesh_finish_generation(FrameLensMesh *mesh,
const size_t old_count = mesh->triangle_count;
LensTriangle *children = calloc(old_count * 4, sizeof *children);
if (children == NULL) {
free(edges); free(requested); free(allowed);
free(edges); free(requested); free(allowed); free(parity); free(jacobians);
return -1;
}
size_t child_count = 0;
@@ -634,7 +659,7 @@ int frame_lens_mesh_finish_generation(FrameLensMesh *mesh,
mesh->vertex_count = next_vertex;
mesh->sample_count = 0;
mesh->samples_include_probes = 0;
free(edges); free(requested); free(allowed);
free(edges); free(requested); free(allowed); free(parity); free(jacobians);
return (int)midpoint_count;
}