mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
ifcgeom: butt-join near-tangent sweep corners instead of hanging #8400
A second, independent trigger for the MakePipeShell hang from #8400: a kink angle at a directrix joint in roughly the 0.57-5 degree band produces two nearly-coaxial pipe surfaces at the corner, and BRepFill_TrimShellCorner's projection (ProjLib_CompProjectedCurve::Init) never converges. This happens regardless of chord length, so the sub-radius chord collapse already fixed in the directrix-hang commit does not prevent it. BRepOffsetAPI_MakePipeShell::SetTransitionMode always leaves Angmin (the kink angle below which OCCT treats a joint as a safe butt-join rather than routing it through the corner trim) at its hardcoded default of 1e-2 rad, and does not expose a way to change it. Confirmed by pulling the OCCT 7.9.2 source: the wrapper is a 1:1 forwarding layer over BRepFill_PipeShell (same Add/Set/Build/ FirstShape/LastShape/Shape semantics), and its own Build() discards the Message_ProgressRange argument it declares, so no progress/cancellation signal reaches this path either way. Switch to BRepFill_PipeShell directly and raise Angmin to 0.1 rad (~5.7 deg) so the dangerous band takes the butt-join path. Verified against the reporter's minimal repro (IfcCableCarrierSegment, 101- segment composite curve directrix, disk radius 1.6cm, kink angles 0.15-2 deg): clean v0.8.0 and v0.8.0 with only the prior directrix-collapse fix both still hang (30s+ timeout, matches the reported bug); with this change it converts in ~1s (4781 verts, 5684 faces, no validation errors). Independently bisected the Angmin threshold on this repro: 0.02 rad still hangs, 0.06 rad fails cleanly ("BRep_API: command not done", no hang), 0.1 rad converges. Regression-checked all 50 test/input fixtures containing IfcSweptDiskSolid (the ones parseable under this build's IFC4-only schema config produce identical exit codes and, where conversion succeeds outright, identical output, before and after) and a synthetic 30 degree corner (well above the new threshold): byte-identical output, confirming ordinary corners are unaffected. One real fixture (987--cableSegment) has joints that fall in the newly-affected band and now converts with fewer vertices/faces at those corners (butt-join instead of trim); both variants pass --validate with no errors, and nearest-neighbour vertex deviation between the two outputs peaks under 1mm on a 3.9mm-radius cable, i.e. a real but small and bounded fidelity trade at corners that previously could hang forever. Generated with the assistance of an AI coding tool.
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
#include "wire_utils.h"
|
||||
|
||||
#include <BRepOffsetAPI_MakePipeShell.hxx>
|
||||
#include <BRepFill_PipeShell.hxx>
|
||||
#include <Geom_Plane.hxx>
|
||||
#include <ShapeAnalysis_Surface.hxx>
|
||||
#include <BRepBuilderAPI_Transform.hxx>
|
||||
@@ -355,20 +356,22 @@ bool OpenCascadeKernel::convert(const taxonomy::sweep_along_curve::ptr scs, Topo
|
||||
continue;
|
||||
}
|
||||
|
||||
BRepOffsetAPI_MakePipeShell builder(wire);
|
||||
builder.Add(section);
|
||||
builder.SetTransitionMode(contains_circular_segments(wire) && wire_is_c1_continuous(wire, 1.e-2) ? BRepBuilderAPI_Transformed : BRepBuilderAPI_RightCorner);
|
||||
// Raise Angmin so near-tangent corners butt-join instead of hanging in
|
||||
// BRepFill_TrimShellCorner (#8400); not exposed via BRepOffsetAPI_MakePipeShell.
|
||||
const double transition_angmin = 0.1; // rad, ~5.7 deg
|
||||
Handle(BRepFill_PipeShell) builder = new BRepFill_PipeShell(wire);
|
||||
builder->Add(section);
|
||||
builder->SetTransition(contains_circular_segments(wire) && wire_is_c1_continuous(wire, 1.e-2) ? BRepFill_Modified : BRepFill_Right, transition_angmin);
|
||||
if (directrix_on_plane) {
|
||||
builder.SetMode(pln.Axis().Direction());
|
||||
builder->Set(pln.Axis().Direction());
|
||||
} else if (!is_plane) {
|
||||
builder.SetMode(surface_face);
|
||||
builder->Set(surface_face);
|
||||
}
|
||||
builder.Build();
|
||||
if (!builder.IsDone()) {
|
||||
if (!builder->Build()) {
|
||||
return false;
|
||||
}
|
||||
auto w0 = TopoDS::Wire(builder.FirstShape());
|
||||
auto w1 = TopoDS::Wire(builder.LastShape());
|
||||
auto w0 = TopoDS::Wire(builder->FirstShape());
|
||||
auto w1 = TopoDS::Wire(builder->LastShape());
|
||||
if (mf0) {
|
||||
mf0->Add(w0);
|
||||
mf1->Add(w1);
|
||||
@@ -382,7 +385,7 @@ bool OpenCascadeKernel::convert(const taxonomy::sweep_along_curve::ptr scs, Topo
|
||||
mf1.reset(new BRepBuilderAPI_MakeFace(f1));
|
||||
}
|
||||
|
||||
for (TopExp_Explorer exp2(builder.Shape(), TopAbs_FACE); exp2.More(); exp2.Next()) {
|
||||
for (TopExp_Explorer exp2(builder->Shape(), TopAbs_FACE); exp2.More(); exp2.Next()) {
|
||||
BB.Add(comp, exp2.Current());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user