Frame: gate fold refinement by Jacobian
This commit is contained in:
1 parent
4c575fa8b5
commit
b95c6579bd
4 files changed
+65
-31
No files matched your search
+37
-12
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user