Skip to content

Mesh - BRepMesh_IncrementalMesh::initParameters refuses a NaN parameter - #1598

Open
gsdali wants to merge 1 commit into
Open-Cascade-SAS:IRfrom
SecondMouseAU:fix/incrementalmesh-initparameters-nan
Open

gsdali wants to merge 1 commit into
Open-Cascade-SAS:IRfrom
SecondMouseAU:fix/incrementalmesh-initparameters-nan

Conversation

@gsdali

@gsdali gsdali commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Pre-Submission Checks

  • I checked existing issues, pull requests, discussions, and forum topics for related work.
  • I followed the contribution guidance in .github/CONTRIBUTING.md.
  • I used a PR title in the Group - Summary format.

Problem / Motivation

BRepMesh_IncrementalMesh::initParameters is the one place the kernel validates the meshing parameters, and it spells all five tests as value < bound:

if (myParameters.Deflection < Precision::Confusion())         { throw Standard_NumericError(...); }
if (myParameters.DeflectionInterior < Precision::Confusion()) { myParameters.DeflectionInterior = myParameters.Deflection; }
if (myParameters.MinSize < Precision::Confusion())            { myParameters.MinSize = ...; }
if (myParameters.Angle < Precision::Angular())                { throw Standard_NumericError(...); }
if (myParameters.AngleInterior < Precision::Angular())        { myParameters.AngleInterior = 2.0 * myParameters.Angle; }

Every comparison with NaN is false. A NaN parameter therefore takes none of the five branches: the two tests that refuse do not refuse, the three that substitute a usable value do not substitute, and the NaN reaches the mesher. The two throws are literal throw statements, so they are live in a release build; an ordinary too-small value is refused promptly, and NaN is the one input that walks through.

What it does depends on the parameter, measured on BRepPrimAPI_MakeCylinder(10, 5) against 8.0.1, one process per case:

  • NaN Deflection: the tessellation did not return in 600 s. On a box, whose faces are all planar, it returned a mesh at no stated deflection (24 nodes); on a free circular edge it produced 22 216 Poly_Polygon3D nodes where a valid request produces 33.
  • NaN Angle, at linear deflection 10 so that the angle decides: IsDone() true, Angle and AngleInterior NaN, 18 nodes against 254 for angle 0.05 to 0.2. The coarsest mesh the linear rule accepts, reported as done.

Proposed Solution

  • Spell the five tests !(value >= bound). An unordered comparison makes >= false, so NaN goes to the refusing or substituting branch. For every ordered value the two spellings are the same test, so no bound moves and no valid input changes behaviour. This is a NaN fix only.
  • Deflection and Angle are validated before the expressions that consume them ((std::min)(Deflection, DeflectionInterior) in the MinSize substitution, 2.0 * Angle in the AngleInterior one), so the substitutions cannot manufacture a NaN of their own from a NaN they were handed.
  • The three substituting tests (DeflectionInterior, MinSize, AngleInterior) are changed for the invariant of the function rather than for a measured defect: a NaN AngleInterior reaching it with a valid Angle did not change the node or triangle count on either fixture I tried. They are included because a function whose contract is that nothing out of bounds reaches the mesher should not leave three of its five tests open to the one value that defeats all of them.

Other users of the same pattern (Prs3d::GetDeflection, the incmesh Draw command) are not touched: every value they pass on arrives here.

Validation

Local build of current IR (Release, BUILD_RELEASE_DISABLE_EXCEPTIONS on as CI builds it, macOS arm64, clang), OpenCascadeGTest. New tests in BRepMesh_IncrementalMesh_Test.cxx:

test IR without the source change with the change
BRepMesh_IncrementalMeshTest.NaNDeflection_IsRefused fail: throws nothing pass
BRepMesh_IncrementalMeshTest.NaNAngle_IsRefused fail: throws nothing pass
BRepMesh_IncrementalMeshTest.NaNOptionalParameters_AreReplaced fail: all three remain NaN pass
BRepMesh_IncrementalMeshTest.OutOfRangeParameters_StayRefused (control: 0 and negative values still throw, a valid request still meshes) pass pass

The deflection test uses a box on purpose: on a cylinder the unpatched 8.0.1 kernel did not return for a NaN deflection.

With the change, the mesh-related suites (*Mesh*, *Triangulation*, *Discret*, RWMesh*, *Tessell*): 141 tests, 141 passed.

Checks performed:

  • Relevant tests were added or updated when applicable.
  • Relevant local tests were run.

clang-format 18.1.8 with the repository .clang-format, the license check and the include cleanup of the formatting job report no change on the touched files, and none contains a non-ASCII character.

Review Notes

The change is confined to the private inline initParameters in the header, called from BRepMesh_IncrementalMesh::Perform only.

initParameters validates five meshing parameters with tests of the form
"value < bound". Every comparison with NaN is false, so a NaN parameter takes
none of the five branches: the two tests that throw do not throw, the three that
substitute a value do not substitute, and the NaN reaches the mesher.

Write the five tests as !(value >= bound), which sends NaN to the refusing or
substituting branch and leaves every ordered value on the branch it took before.

Add GTests for a NaN deflection and angle, for NaN optional parameters being
replaced, and for out-of-range values staying refused.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

1 participant