mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 17:58:20 +00:00
Fix cgal kernel under-tessellating large-radius arcs (#8051)
The CGAL kernels (cgal and cgal-simple) allocate arc segments as a fraction of the full circle via CircleSegments, ignoring the radius. A large-radius arc that spans a small angle therefore collapsed to a single chord, turning curved curtain-wall mullions straight while the OpenCascade kernel (which meshes by deflection) kept them curved. evaluate_conic now also enforces a deflection-based floor on the number of segments, keeping the chord deviation within mesher-linear-deflection, matching OpenCascade. Small circles are unchanged (CircleSegments floor still dominates); only large-radius curves get denser. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
committed by
Thomas Krijnen
parent
eb7324e7fc
commit
dd9fa65629
@@ -391,6 +391,11 @@ namespace {
|
||||
}
|
||||
};
|
||||
|
||||
// Representative radius used to size the polygonal approximation of a conic.
|
||||
// For an ellipse the larger semi-axis is the conservative choice.
|
||||
inline double conic_radius(const taxonomy::circle::ptr& c) { return c->radius; }
|
||||
inline double conic_radius(const taxonomy::ellipse::ptr& e) { return e->radius > e->radius2 ? e->radius : e->radius2; }
|
||||
|
||||
struct cgal_curve_creation_visitor {
|
||||
Settings& settings_;
|
||||
parameter_range param;
|
||||
@@ -425,7 +430,28 @@ namespace {
|
||||
if (b <= a) {
|
||||
b += 2 * M_PI;
|
||||
}
|
||||
int num_segments = (int)std::ceil(std::fabs(a - b) / (2 * M_PI) * settings_.get<settings::CircleSegments>().get());
|
||||
const double span = std::fabs(a - b);
|
||||
int num_segments = (int)std::ceil(span / (2 * M_PI) * settings_.get<settings::CircleSegments>().get());
|
||||
// CircleSegments allocates segments as a fraction of the *full* circle and is
|
||||
// radius-agnostic. A large-radius arc spanning a small angle therefore collapses
|
||||
// to a single chord (issue #8051: curved curtain-wall mullions became straight in
|
||||
// the CGAL kernels while OpenCascade, which meshes by deflection, kept them curved).
|
||||
// Enforce a deflection-based floor so the chord deviation stays within the mesher's
|
||||
// linear deflection, matching OpenCascade behaviour.
|
||||
const double radius = conic_radius(t);
|
||||
const double deflection = settings_.get<settings::MesherLinearDeflection>().get();
|
||||
if (deflection > 0. && radius > deflection) {
|
||||
const double max_segment_angle = 2.0 * std::acos(1.0 - deflection / radius);
|
||||
if (max_segment_angle > 0.) {
|
||||
const int num_segments_deflection = (int)std::ceil(span / max_segment_angle);
|
||||
if (num_segments_deflection > num_segments) {
|
||||
num_segments = num_segments_deflection;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (num_segments < 1) {
|
||||
num_segments = 1;
|
||||
}
|
||||
double du = (b - a) / num_segments;
|
||||
taxonomy::point3 P;
|
||||
// @nb for loop is not inclusive of the both end points
|
||||
|
||||
Reference in New Issue
Block a user