Use exact topology points at parametric range bounds to guarantee welding #4487

This commit is contained in:
Thomas Krijnen
2025-04-18 10:08:57 +02:00
parent ad0f62f88f
commit 21d39d8a23
2 changed files with 31 additions and 2 deletions
@@ -248,8 +248,34 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(ifcopenshell::geometr
int previous = -1;
const bool reversed = texp.Value().Orientation() == TopAbs_REVERSED;
bool first = true;
gp_Pnt p0, p1;
double u0 = std::numeric_limits<double>::quiet_NaN(), u1 = std::numeric_limits<double>::quiet_NaN();
if (auto crv = BRep_Tool::Curve(TopoDS::Edge(texp.Value()), u0, u1)) {
TopoDS_Vertex v0, v1;
TopExp::Vertices(TopoDS::Edge(texp.Value()), v0, v1, false);
if (!v0.IsNull() && !v1.IsNull()) {
p0 = BRep_Tool::Pnt(v0);
p1 = BRep_Tool::Pnt(v1);
} else {
u0 = u1 = std::numeric_limits<double>::quiet_NaN();
}
}
for (int i = (reversed ? n : 1); reversed ? (i >= 1) : (i <= n); i += reversed ? -1 : 1) {
gp_XYZ p = tessellater.Value(i).XYZ();
gp_XYZ p;
if (std::fabs(tessellater.Parameter(i) - u0) < 1.e-7) {
// Use the exact points from the topology when parameter is close to the begin or end of the parametric range
// This guarantees points are properly welded, because the GCPnts_QuasiUniformDeflection could otherwise introduce
// minor differences between the approximated points from shared vertices.
// @todo Using GCPnts_QuasiUniformDeflection on linear edges is pure lazyness
p = p0.XYZ();
} else if (std::fabs(tessellater.Parameter(i) - u1) < 1.e-7) {
p = p1.XYZ();
} else {
p = tessellater.Value(i).XYZ();
}
auto p_local = p;
taxonomy_transform(place.components_, p);