Skip to content

Nef_3: Fix ID_support_handler logic error - #9478

Open
GilesBathgate wants to merge 1 commit into
CGAL:mainfrom
GilesBathgate:Nef_3-fix_id_support_handler-GilesBathgate
Open

Nef_3: Fix ID_support_handler logic error#9478
GilesBathgate wants to merge 1 commit into
CGAL:mainfrom
GilesBathgate:Nef_3-fix_id_support_handler-GilesBathgate

Conversation

@GilesBathgate

@GilesBathgate GilesBathgate commented May 13, 2026

Copy link
Copy Markdown
Contributor

Summary of Changes

This fixes a logical error in ID_support_handler (probably caused by a typo)

First I should explain that in this code:

int index1 = get_hash(se1->get_index());
int index2 = get_hash(sl2->get_index());
if(index1 < index2) {
se->set_index(index1);
set_hash(se1->get_index(), index1);
set_hash(sl2->get_index(), index1);
} else {
se->set_index(index2);
set_hash(se1->get_index(), index2);
set_hash(sl2->get_index(), index2);
}

The assignment of se1's hashed index to se1's hashed index (line 308) is a no-op H[x₁] ← H[x₁]
likewise the assignment of sl2's hashed index to sl2's hashed index (line 313) is a no-op. These no-op's don't really matter but for the sake of correctness I've removed them. The real problem is with this code:

set_hash(se1->twin()->get_index(), index1);

The intention here isn't a no-op the intention is for it to merge the indexes using the union find.
set_hash(se2->twin()->get_index(), index1);

I have created a failing test that passes when the fix is applied. However in a more general sense this bug doesn't create a topological, or geometric flaw, because in the correct logic is applied in another pass:

int index1 = A.get_hash(e->get_index());
int index2 = A.get_hash(en->get_index());
if(index2 < index1) {
A.set_hash(e->get_index(), index2);
e->set_index(index2);
} else
A.set_hash(en->get_index(), index1);
index1 = A.get_hash(eo->get_index());
index2 = A.get_hash(eno->get_index());
if(index2 < index1) {
A.set_hash(eo->get_index(), index2);
eo->set_index(index2);
} else
A.set_hash(eno->get_index(), index1);

In certain cases cycling the svertices means visiting the same halfedges via each local sphere but with the indexes reversed (index2 < index1) so it falls into the branch of code where the logic is correct.

Release Management

  • Affected package(s): Nef_3
  • Issue(s) solved (if any): fix bug
  • License and copyright ownership: CGAL

@GilesBathgate

GilesBathgate commented May 15, 2026

Copy link
Copy Markdown
Contributor Author

A better approach would be to refactor the code duplication into something like this:

int unify_indices(int idx1, int idx2) {
    int root1 = get_hash(idx1);
    int root2 = get_hash(idx2);

    if (root1 == root2) return root2;

    // Union by ID: The numerically smaller index becomes the parent
    if (root1 < root2) {
        set_hash(idx2, root1);
        return root1;
    } else {
        set_hash(idx1, root2);
        return root2;
    }
}

Then replace the repeated code with:

int index = unify_indices(se1->get_index(), se2->get_index());
se->set_index(index);

index = unify_indices(se1->twin()->get_index(), se2->twin()->get_index());
se->twin()->set_index(index);

Should that be out of scope for a simple bug fix?

@sloriot
sloriot requested a review from afabri July 15, 2026 18:24
@sloriot

sloriot commented Jul 15, 2026

Copy link
Copy Markdown
Member

Successfully tested in CGAL-6.3-Ic-31

@sloriot sloriot added Not yet approved The feature or pull-request has not yet been approved. Tested Pkg::Nef_3 and removed Under Testing labels Jul 15, 2026
@afabri

afabri commented Jul 20, 2026

Copy link
Copy Markdown
Member

Can you please also add the testcase that produces an error. Does it segfault, trigger an assertion, or "only" produce a wrong result?
And I would go for the refactoring you propose. That is much nicer than a no-op needed for its side effect.

const int id3 = 20;
const int id4 = 21;

// edge-edge

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@afabri The test case is already added. As mentioned in the summary, the test fails without the fix applied.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Not yet approved The feature or pull-request has not yet been approved. Pkg::Nef_3 Tested

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants