Work-around for tiny radii sweeps #5474

This commit is contained in:
Thomas Krijnen
2024-10-08 14:53:56 +02:00
parent 89b1f9c2d7
commit 36a0a0f2dd
4 changed files with 60 additions and 6 deletions
@@ -128,7 +128,7 @@ public:
const IfcGeom::ConversionResults& entity_shapes, const ifcopenshell::geometry::taxonomy::matrix4& entity_trsf, IfcGeom::ConversionResults& cut_shapes);
virtual bool unify_shapes(const IfcGeom::ConversionResults& input, IfcGeom::ConversionResults& output);
typedef boost::variant<Handle(Geom_Curve), TopoDS_Wire> curve_creation_visitor_result_type;
typedef boost::variant<boost::blank, Handle(Geom_Curve), TopoDS_Wire> curve_creation_visitor_result_type;
curve_creation_visitor_result_type convert_curve(const ifcopenshell::geometry::taxonomy::ptr);
Handle(Geom_Surface) convert_surface(const ifcopenshell::geometry::taxonomy::ptr);
+4 -2
View File
@@ -151,7 +151,7 @@ namespace {
// It's a bit more convenient to use high level BRepPrimAPI calls that operate on
// topology. On a single edge that will create a Geom_TrimmedCurve for us.
auto crv_or_wire = kernel->convert_curve(i);
if (crv_or_wire.which() == 1) {
if (crv_or_wire.which() == 2) {
const auto& w = boost::get<TopoDS_Wire>(crv_or_wire);
return w;
} else {
@@ -163,8 +163,10 @@ namespace {
// @todo unify with trimmed curve handling
auto crv_or_wire = kernel->convert_curve(i);
if (crv_or_wire.which() == 0) {
throw std::runtime_error("Failed to obtain curve");
} else if (crv_or_wire.which() == 1) {
return boost::get<Handle(Geom_Curve)>(crv_or_wire);
} else {
} else if (crv_or_wire.which() == 2) {
// @todo
const double precision_ = 1.e-5;
Logger::Warning("Approximating BasisCurve due to possible discontinuities", i->instance);
+16 -1
View File
@@ -18,6 +18,7 @@
#include <BRep_Tool.hxx>
#include <TopTools_ListOfShape.hxx>
#include <BRepTools_WireExplorer.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <Standard_Version.hxx>
#if OCC_VERSION_HEX < 0x70600
@@ -98,7 +99,7 @@ namespace {
if (!kernel->convert(l, wire)) {
throw std::runtime_error("Failed to convert loop to wire");
}
return result;
return result = wire;
}
OpenCascadeKernel::curve_creation_visitor_result_type operator()(const taxonomy::edge::ptr& e) {
@@ -119,6 +120,9 @@ namespace {
auto crv_or_wire = kernel->convert_curve(e_basis);
Handle(Geom_Curve) curve;
if (crv_or_wire.which() == 0) {
// raise exception
return result;
} else if (crv_or_wire.which() == 1) {
curve = boost::get<Handle(Geom_Curve)>(crv_or_wire);
} else {
// @todo
@@ -355,6 +359,17 @@ bool OpenCascadeKernel::convert(const taxonomy::loop::ptr loop, TopoDS_Wire& wir
wire = mw.Wire();
}
if (loop->matrix && !loop->matrix->is_identity()) {
const auto& m = loop->matrix->ccomponents();
gp_Trsf tr;
tr.SetValues(
m(0, 0), m(0, 1), m(0, 2), m(0, 3),
m(1, 0), m(1, 1), m(1, 2), m(1, 3),
m(2, 0), m(2, 1), m(2, 2), m(2, 3)
);
wire = TopoDS::Wire(BRepBuilderAPI_Transform(wire, tr).Shape());
}
return true;
}
@@ -34,8 +34,9 @@ using namespace IfcGeom::util;
bool OpenCascadeKernel::convert(const taxonomy::sweep_along_curve::ptr scs, TopoDS_Shape& result) {
auto w = convert_curve(scs->curve);
if (w.which() == 0) {
if (w.which() != 2) {
Logger::Error("Unsupported directrix");
return false;
}
TopoDS_Shape face;
convert(taxonomy::cast<taxonomy::face>(scs->basis), face);
@@ -136,6 +137,9 @@ bool OpenCascadeKernel::convert(const taxonomy::sweep_along_curve::ptr scs, Topo
builder.SetMode(surface_face);
}
builder.Build();
if (!builder.IsDone()) {
return false;
}
builder.MakeSolid();
result = builder.Shape();
@@ -144,12 +148,45 @@ bool OpenCascadeKernel::convert(const taxonomy::sweep_along_curve::ptr scs, Topo
bool OpenCascadeKernel::convert_impl(const taxonomy::sweep_along_curve::ptr scs, IfcGeom::ConversionResults& results) {
TopoDS_Shape shape;
// For tiny radii occt will fail building the sweep, in which case we enlarge the inputs to occt, and add a scale matrix to the output
bool enlarged = false;
static double enlarge_factor = 1000.;
if (scs->basis->kind() == taxonomy::FACE) {
auto w = std::static_pointer_cast<taxonomy::face>(scs->basis)->children[0];
if (w->children.size() == 1 && w->children[0]->basis && w->children[0]->basis->kind() == taxonomy::CIRCLE) {
auto circ = std::static_pointer_cast<taxonomy::circle>(w->children[0]->basis);
enlarged = circ->radius < 1.e-4;
if (enlarged) {
// @todo immutability
circ->radius *= enlarge_factor;
auto crv = std::static_pointer_cast<taxonomy::geom_item>(scs->curve);
if (crv->matrix) {
crv->matrix = taxonomy::make<taxonomy::matrix4>(
Eigen::Scaling(enlarge_factor) *
crv->matrix->ccomponents()
);
} else {
crv->matrix = taxonomy::make<taxonomy::matrix4>();
crv->matrix->components().topLeftCorner<3, 3>() = Eigen::Scaling(enlarge_factor, enlarge_factor, enlarge_factor).toDenseMatrix();
}
}
}
}
if (!convert(scs, shape)) {
return false;
}
taxonomy::matrix4::ptr m;
if (enlarged) {
m = taxonomy::make<taxonomy::matrix4>(
Eigen::Scaling(1. / enlarge_factor) *
scs->matrix->ccomponents()
);
} else {
m = scs->matrix;
}
results.emplace_back(ConversionResult(
scs->instance->as<IfcUtil::IfcBaseEntity>()->id(),
scs->matrix,
m,
new OpenCascadeShape(shape),
scs->surface_style
));