build: update OCCT to 8.0.1 (faster STEP and Design tab, Windows STEP crash fix) (#16089)

This commit is contained in:
Kris Austin authored and GitHub committed 2026-10-04 12:36:54 -03:00
1 parent 0fd04ff07c
commit 78a4f2867c
22 files changed
+1665 -476

No files matched your search

+24 -39
View File
@@ -37,10 +37,9 @@
#include <cstdint>
#include <cereal/cereal.hpp>
#include <gp_Pln.hxx>
#include <TopTools_ListOfShape.hxx>
#include <NCollection_List.hxx>
#include <BRepPrimAPI_MakeCylinder.hxx>
#include <BRepPrimAPI_MakeCone.hxx>
#include <BRepPrimAPI_MakePrism.hxx>
#include <BRepPrimAPI_MakeRevol.hxx>
#include <BRepCheck_Analyzer.hxx>
#include <BRepLib.hxx>
@@ -53,7 +52,7 @@
#include <Geom_ConicalSurface.hxx>
#include <Geom2d_TrimmedCurve.hxx>
#include <GeomAbs_Shape.hxx> // SurfaceFill: GeomAbs_C0
#include <GCE2d_MakeSegment.hxx>
#include <GC_MakeSegment2d.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <TopAbs.hxx>
@@ -105,7 +104,7 @@ static TopoDS_Wire make_helix_wire(const gp_Ax3& axis, double radius,
// In the surface (u,v) parametrization u is the angle, v the axial height.
gp_Pnt2d p0(0.0, 0.0);
gp_Pnt2d p1(2.0 * M_PI * turns, height);
Handle(Geom2d_TrimmedCurve) seg = GCE2d_MakeSegment(p0, p1);
Handle(Geom2d_TrimmedCurve) seg = GC_MakeSegment2d(p0, p1);
TopoDS_Edge e = BRepBuilderAPI_MakeEdge(seg, cyl).Edge();
BRepLib::BuildCurves3d(e);
return BRepBuilderAPI_MakeWire(e).Wire();
@@ -147,14 +146,14 @@ static TopoDS_Wire make_helix_spine(const CadFeature& f, std::string& err)
double u1 = f.helix_left_handed ? -2.0 * M_PI * turns : 2.0 * M_PI * turns;
gp_Pnt2d p0(0.0, 0.0);
gp_Pnt2d p1(u1, H);
Handle(Geom2d_TrimmedCurve) seg = GCE2d_MakeSegment(p0, p1);
Handle(Geom2d_TrimmedCurve) seg = GC_MakeSegment2d(p0, p1);
e = BRepBuilderAPI_MakeEdge(seg, cone).Edge();
} else {
Handle(Geom_CylindricalSurface) cyl = new Geom_CylindricalSurface(ax3, R);
double u1 = f.helix_left_handed ? -2.0 * M_PI * turns : 2.0 * M_PI * turns;
gp_Pnt2d p0(0.0, 0.0);
gp_Pnt2d p1(u1, H);
Handle(Geom2d_TrimmedCurve) seg = GCE2d_MakeSegment(p0, p1);
Handle(Geom2d_TrimmedCurve) seg = GC_MakeSegment2d(p0, p1);
e = BRepBuilderAPI_MakeEdge(seg, cyl).Edge();
}
BRepLib::BuildCurves3d(e);
@@ -193,7 +192,7 @@ static TopoDS_Wire make_thread_profile(const gp_Pnt& origin, const gp_Dir& xdir,
gp_Pnt top (origin.XYZ() + (vx * inner).XYZ() + (vz * ( half)).XYZ());
gp_Pnt bot (origin.XYZ() + (vx * inner).XYZ() + (vz * (-half)).XYZ());
gp_Pnt apex(origin.XYZ() + (vx * crest).XYZ());
BRepBuilderAPI_MakePolygon poly(top, bot, apex, Standard_True);
BRepBuilderAPI_MakePolygon poly(top, bot, apex, true);
return poly.Wire(); // closed triangle, swept by MakePipeShell with a fixed binormal
}
@@ -2368,10 +2367,12 @@ void CadDocument::apply_feature(TopoDS_Shape& result, bool& have_body,
TopoDS_Wire wire = build_sketch_wire(sk);
if (wire.IsNull()) throw std::runtime_error("surface-extrude: empty profile");
gp_Dir nrm(sk.plane.normal.x(), sk.plane.normal.y(), sk.plane.normal.z());
gp_Vec v(nrm.XYZ() * f.distance);
TopoDS_Shape shell = BRepPrimAPI_MakePrism(wire, v, false, true).Shape();
if (shell.IsNull()) throw std::runtime_error("surface-extrude: prism failed");
result = shell; have_body = true;
try {
result = SketchEngine::make_prism(wire, gp_Vec(nrm.XYZ() * f.distance));
} catch (const std::exception& e) {
throw std::runtime_error(std::string("surface-extrude: ") + (*e.what() ? e.what() : "prism failed"));
}
have_body = true;
break;
}
case CadFeatureType::SurfaceRevolve: {
@@ -2584,7 +2585,7 @@ void CadDocument::apply_feature(TopoDS_Shape& result, bool& have_body,
double h = f.rib_thickness * 0.5;
Vec2d q0 = a + perp*h, q1 = b + perp*h, q2 = b - perp*h, q3 = a - perp*h;
auto w3 = [&](const Vec2d& p){ Vec3d w = pl.to_world(p); return gp_Pnt(w.x(),w.y(),w.z()); };
BRepBuilderAPI_MakePolygon poly(w3(q0), w3(q1), w3(q2), w3(q3), Standard_True);
BRepBuilderAPI_MakePolygon poly(w3(q0), w3(q1), w3(q2), w3(q3), true);
if (!poly.IsDone()) throw std::runtime_error("rib: profile failed");
TopoDS_Shape wall = SketchEngine::make_extrude(poly.Wire(), pl, f.rib_depth, false, 0.0);
if (wall.IsNull()) throw std::runtime_error("rib: extrude failed");
@@ -2746,7 +2747,7 @@ void CadDocument::apply_feature(TopoDS_Shape& result, bool& have_body,
if (!have_body) throw std::runtime_error("shell needs a body");
// Hollow the body to a wall thickness; the picked face (if any) is removed so the
// shell is open there. MakeThickSolidByJoin with a NEGATIVE offset shells inward.
TopTools_ListOfShape remove;
NCollection_List<TopoDS_Shape> remove;
if (f.shell_face >= 0) {
TopoDS_Face fc = GeometryEngine::face_by_index(result, f.shell_face);
if (!fc.IsNull()) remove.Append(fc);
@@ -2769,7 +2770,7 @@ void CadDocument::apply_feature(TopoDS_Shape& result, bool& have_body,
// ponytail: neutral plane / pull direction fixed to world up; pick-based neutral plane
// deferred (same as the datum-plane pick types, dgv).
Bnd_Box bb; BRepBndLib::Add(result, bb);
Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
double xmin, ymin, zmin, xmax, ymax, zmax;
bb.Get(xmin, ymin, zmin, xmax, ymax, zmax);
gp_Dir pull(0, 0, 1);
gp_Pln neutral(gp_Pnt(0, 0, zmin), pull);
@@ -2850,7 +2851,7 @@ void CadDocument::apply_boolean(std::vector<CadBody>& bodies, const CadFeature&
const TopoDS_Shape B = bodies[tool].shape; // tool, consumed unless kept
if (A.IsNull() || B.IsNull()) return;
TopTools_ListOfShape args, tools;
NCollection_List<TopoDS_Shape> args, tools;
args.Append(A);
tools.Append(B);
auto run = [&](BRepAlgoAPI_BooleanOperation& bop) -> TopoDS_Shape {
@@ -3091,7 +3092,7 @@ void CadDocument::apply_thicken_surface(std::vector<CadBody>& bodies, const CadF
int n_faces = 0;
for (TopExp_Explorer fe(sheet, TopAbs_FACE); fe.More(); fe.Next()) ++n_faces;
TopTools_ListOfShape caps;
NCollection_List<TopoDS_Shape> caps;
if (n_faces > 1) {
ShapeAnalysis_FreeBounds fb(sheet);
for (TopExp_Explorer we(fb.GetClosedWires(), TopAbs_WIRE); we.More(); we.Next()) {
@@ -3113,7 +3114,7 @@ void CadDocument::apply_thicken_surface(std::vector<CadBody>& bodies, const CadF
} else {
BRepBuilderAPI_Sewing sewer(1.0e-3);
sewer.Add(sheet);
for (TopTools_ListIteratorOfListOfShape it(caps); it.More(); it.Next())
for (NCollection_List<TopoDS_Shape>::Iterator it(caps); it.More(); it.Next())
sewer.Add(it.Value());
sewer.Perform();
@@ -3674,13 +3675,8 @@ bool CadDocument::recompute()
if (b.source_feature < 0)
b.source_feature = int(fi);
}
} catch (const Standard_Failure& e) {
// OCCT raises Standard_Failure (NOT a std::exception) — must be caught
// here or it escapes the event handler and terminates the app.
error = e.GetMessageString() ? e.GetMessageString() : "OCCT operation failed";
return false;
} catch (const std::exception& e) {
error = e.what();
error = *e.what() ? e.what() : "OCCT operation failed";
return false;
} catch (...) {
error = "unknown geometry error";
@@ -3782,11 +3778,8 @@ bool CadDocument::preview(const CadFeature& candidate, TriangleMesh& out_mesh,
std::vector<CadBody> tmp = bodies; // start from the current committed bodies
try {
route_feature(tmp, candidate); // candidate may append a new body or mutate one
} catch (const Standard_Failure& e) {
err = e.GetMessageString() ? e.GetMessageString() : "OCCT operation failed";
return false;
} catch (const std::exception& e) {
err = e.what();
err = *e.what() ? e.what() : "OCCT operation failed";
return false;
} catch (...) {
err = "unknown geometry error";
@@ -3986,13 +3979,9 @@ bool CadDocument::deserialize_recipe(const std::string& blob)
error = "saved with an older version of the Design tab (format v"
+ std::to_string(v) + "); this project cannot be opened by this build";
return false;
} catch (const Standard_Failure& e) {
const char* what = e.GetMessageString();
error = std::string("CAD data could not be read")
+ (what && *what ? ": " + std::string(what) : "");
return false;
} catch (const std::exception& e) {
error = std::string("CAD data could not be read: ") + e.what();
error = std::string("CAD data could not be read")
+ (*e.what() ? ": " + std::string(e.what()) : "");
return false;
} catch (...) {
error = "CAD data could not be read";
@@ -4034,11 +4023,8 @@ bool CadDocument::export_step(const std::string& path,
err = "cannot write STEP file";
return false;
}
} catch (const Standard_Failure& e) {
err = e.GetMessageString() ? e.GetMessageString() : "OCCT failed to write STEP";
return false;
} catch (const std::exception& e) {
err = e.what();
err = *e.what() ? e.what() : "OCCT failed to write STEP";
return false;
}
return true;
@@ -4109,8 +4095,7 @@ std::vector<CadDocument::Interference> CadDocument::check_interference(double mi
if (bodies[j].shape.IsNull() || is_sheet_shape(bodies[j].shape)) continue;
double v = 0;
// A boolean that blows up on one pair must not lose the report for the others,
// and OCCT signals those as Standard_Failure, which is NOT a std::exception.
// A boolean that fails on one pair must not lose the report for the others.
try {
BRepAlgoAPI_Common common(bodies[i].shape, bodies[j].shape);
common.Build();
+14 -11
View File
@@ -27,9 +27,10 @@
#include <TopoDS_Edge.hxx>
#include <TopExp.hxx>
#include <TopTools.hxx>
#include <TopTools_IndexedMapOfShape.hxx>
#include <TopTools_ListOfShape.hxx>
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
#include <TopTools_ShapeMapHasher.hxx>
#include <NCollection_IndexedDataMap.hxx>
#include <NCollection_IndexedMap.hxx>
#include <NCollection_List.hxx>
#include <Poly_Triangulation.hxx>
#include <gp_Ax2.hxx>
#include <gp_Dir.hxx>
@@ -62,6 +63,8 @@
namespace Slic3r {
using ShapeIndexMap = NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher>;
// ---- STEP import (B-rep, not mesh) ----
std::vector<TopoDS_Shape> GeometryEngine::read_step_solids(const std::string& path, std::string& err)
{
@@ -82,7 +85,7 @@ std::vector<TopoDS_Shape> GeometryEngine::read_step_solids(const std::string& pa
if (out.empty())
out.push_back(shape);
} catch (const Standard_Failure& e) {
err = e.GetMessageString() ? e.GetMessageString() : "OCCT failed to read STEP";
err = *e.what() ? e.what() : "OCCT failed to read STEP";
out.clear();
}
return out;
@@ -299,13 +302,13 @@ std::vector<TopoDS_Edge> GeometryEngine::collect_edges(const TopoDS_Shape& solid
}
// Build edge-to-face map once
TopTools_IndexedDataMapOfShapeListOfShape edgeFaceMap;
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher> edgeFaceMap;
TopExp::MapShapesAndAncestors(solid, TopAbs_EDGE, TopAbs_FACE, edgeFaceMap);
for (TopExp_Explorer edgeExp(solid, TopAbs_EDGE); edgeExp.More(); edgeExp.Next()) {
const TopoDS_Edge& edge = TopoDS::Edge(edgeExp.Current());
if (!edgeFaceMap.Contains(edge)) continue;
const TopTools_ListOfShape& faces = edgeFaceMap.FindFromKey(edge);
const NCollection_List<TopoDS_Shape>& faces = edgeFaceMap.FindFromKey(edge);
bool include = false;
for (auto it = faces.begin(); it != faces.end(); ++it) {
@@ -569,7 +572,7 @@ std::vector<TopoDS_Face> GeometryEngine::faces_of(const TopoDS_Shape& shape)
std::vector<TopoDS_Edge> GeometryEngine::edges_of(const TopoDS_Shape& shape)
{
TopTools_IndexedMapOfShape map;
ShapeIndexMap map;
TopExp::MapShapes(shape, TopAbs_EDGE, map); // same order as edge_by_index
std::vector<TopoDS_Edge> out;
out.reserve(map.Extent());
@@ -581,7 +584,7 @@ std::vector<TopoDS_Edge> GeometryEngine::edges_of(const TopoDS_Shape& shape)
std::vector<TopoDS_Edge> GeometryEngine::edges_of_face(const TopoDS_Face& face)
{
std::vector<TopoDS_Edge> result;
TopTools_IndexedMapOfShape map;
ShapeIndexMap map;
TopExp::MapShapes(face, TopAbs_EDGE, map);
for (int i = 1; i <= map.Extent(); ++i)
result.push_back(TopoDS::Edge(map(i)));
@@ -704,14 +707,14 @@ bool GeometryEngine::face_plane_bounds(const TopoDS_Face& face, const Vec3d& ori
int GeometryEngine::edge_count(const TopoDS_Shape& shape)
{
TopTools_IndexedMapOfShape map;
ShapeIndexMap map;
TopExp::MapShapes(shape, TopAbs_EDGE, map);
return map.Extent();
}
TopoDS_Edge GeometryEngine::edge_by_index(const TopoDS_Shape& shape, int index)
{
TopTools_IndexedMapOfShape map;
ShapeIndexMap map;
TopExp::MapShapes(shape, TopAbs_EDGE, map);
if (index < 0 || index >= map.Extent())
return TopoDS_Edge();
@@ -720,7 +723,7 @@ TopoDS_Edge GeometryEngine::edge_by_index(const TopoDS_Shape& shape, int index)
int GeometryEngine::edge_index_of(const TopoDS_Shape& shape, const TopoDS_Edge& edge)
{
TopTools_IndexedMapOfShape map;
ShapeIndexMap map;
TopExp::MapShapes(shape, TopAbs_EDGE, map);
int idx = map.FindIndex(edge);
return (idx > 0) ? (idx - 1) : -1;
+27 -29
View File
@@ -27,9 +27,7 @@
#include <GC_MakeArcOfEllipse.hxx>
#include <Geom_TrimmedCurve.hxx>
#include <Geom_BSplineCurve.hxx>
#include <TColgp_Array1OfPnt.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <NCollection_Array1.hxx>
#include <gp_Circ.hxx>
#include <gp_Elips.hxx>
#include <gp_Ax2.hxx>
@@ -179,21 +177,23 @@ TopoDS_Wire SketchProfile::to_occt_wire(const SketchPlane& plane) const
// ---- SketchEngine ----
TopoDS_Shape SketchEngine::make_prism(const TopoDS_Shape& base, const gp_Vec& vec)
{
if (vec.Magnitude() < 1e-9) throw std::runtime_error("extrude depth is zero");
BRepPrimAPI_MakePrism prism(base, vec);
if (!prism.IsDone()) throw std::runtime_error("extrude failed");
return prism.Shape();
}
static TopoDS_Shape extrude_face_internal(const TopoDS_Face& face, const gp_Dir& dir, double length, bool symmetric)
{
gp_Vec vec = gp_Vec(dir) * length;
if (symmetric) {
gp_Vec halfVec = gp_Vec(dir) * (length / 2.0);
BRepPrimAPI_MakePrism pos(face, halfVec);
BRepPrimAPI_MakePrism neg(face, -halfVec);
if (!pos.IsDone() || !neg.IsDone()) throw std::runtime_error("Symmetric extrude failed");
BRepAlgoAPI_Fuse fuse(pos.Shape(), neg.Shape());
BRepAlgoAPI_Fuse fuse(SketchEngine::make_prism(face, halfVec), SketchEngine::make_prism(face, -halfVec));
if (!fuse.IsDone()) throw std::runtime_error("Fuse failed");
return fuse.Shape();
}
BRepPrimAPI_MakePrism prism(face, vec);
if (!prism.IsDone()) throw std::runtime_error("Extrude failed");
return prism.Shape();
return SketchEngine::make_prism(face, gp_Vec(dir) * length);
}
TopoDS_Shape SketchEngine::make_extrude(const TopoDS_Wire& wire, const SketchPlane& plane,
@@ -224,12 +224,9 @@ TopoDS_Shape SketchEngine::make_extrude_two_sided(const TopoDS_Face& face, const
{
gp_Dir dir(plane.normal.x(), plane.normal.y(), plane.normal.z());
const double u = std::abs(up), d = std::abs(down);
if (u < 1e-9 && d < 1e-9) return TopoDS_Shape();
if (d < 1e-9) { BRepPrimAPI_MakePrism p(face, gp_Vec(dir) * u); return p.Shape(); }
if (u < 1e-9) { BRepPrimAPI_MakePrism p(face, gp_Vec(dir) * -d); return p.Shape(); }
BRepPrimAPI_MakePrism pos(face, gp_Vec(dir) * u);
BRepPrimAPI_MakePrism neg(face, gp_Vec(dir) * -d);
BRepAlgoAPI_Fuse fuse(pos.Shape(), neg.Shape());
if (d < 1e-9) return make_prism(face, gp_Vec(dir) * u);
if (u < 1e-9) return make_prism(face, gp_Vec(dir) * -d);
BRepAlgoAPI_Fuse fuse(make_prism(face, gp_Vec(dir) * u), make_prism(face, gp_Vec(dir) * -d));
if (!fuse.IsDone()) throw std::runtime_error("two-sided extrude fuse failed");
return fuse.Shape();
}
@@ -240,8 +237,8 @@ TopoDS_Shape SketchEngine::make_extrude_taper(const TopoDS_Wire& wire, const Ske
gp_Dir dir(plane.normal.x(), plane.normal.y(), plane.normal.z());
auto straight = [&]() -> TopoDS_Shape {
BRepBuilderAPI_MakeFace fm(wire);
BRepPrimAPI_MakePrism prism(fm.Face(), gp_Vec(dir) * length);
return prism.Shape();
if (!fm.IsDone()) throw std::runtime_error("Failed to make face from wire");
return make_prism(fm.Face(), gp_Vec(dir) * length);
};
if (std::abs(taper_deg) >= 89.0 || std::abs(length) < 1e-9) return straight();
const double off = length * std::tan(taper_deg * M_PI / 180.0);
@@ -258,10 +255,10 @@ TopoDS_Shape SketchEngine::make_extrude_taper(const TopoDS_Wire& wire, const Ske
if (topFlat.IsNull()) return straight();
// 2) lift it along the normal by `length`
gp_Trsf tr; tr.SetTranslation(gp_Vec(dir) * length);
BRepBuilderAPI_Transform xf(topFlat, tr, Standard_True);
BRepBuilderAPI_Transform xf(topFlat, tr, true);
TopoDS_Wire topWire = TopoDS::Wire(xf.Shape());
// 3) loft base -> top into a solid
BRepOffsetAPI_ThruSections loft(Standard_True /*solid*/, Standard_False /*ruled*/);
BRepOffsetAPI_ThruSections loft(true /*solid*/, false /*ruled*/);
loft.AddWire(wire);
loft.AddWire(topWire);
loft.Build();
@@ -285,6 +282,9 @@ TopoDS_Shape SketchEngine::make_extrude_regions(
const std::vector<std::vector<std::vector<Vec2d>>>& regions,
const SketchPlane& plane, double length, bool symmetric)
{
// The loop below skips regions that fail, so a zero depth is rejected before it.
if (std::abs(length) < 1e-9) throw std::runtime_error("extrude depth is zero");
// Drop consecutive coincident points and the closing duplicate. FreeType /
// SVG flattening routinely emits repeated points which would build a
// degenerate OCCT edge and make the wire builder throw — sanitising keeps a
@@ -406,8 +406,7 @@ TopoDS_Shape SketchEngine::make_loft(const std::vector<TopoDS_Wire>& profiles, b
{
if (profiles.size() < 2)
throw std::runtime_error("loft needs at least 2 profiles");
BRepOffsetAPI_ThruSections loft(Standard_True /*solid*/,
ruled ? Standard_True : Standard_False);
BRepOffsetAPI_ThruSections loft(true /*solid*/, ruled);
for (const TopoDS_Wire& w : profiles) {
if (w.IsNull()) throw std::runtime_error("loft: null profile wire");
loft.AddWire(w);
@@ -424,8 +423,7 @@ TopoDS_Shape SketchEngine::make_loft_surface(const std::vector<TopoDS_Wire>& pro
{
if (profiles.size() < 2)
throw std::runtime_error("loft needs at least 2 profiles");
BRepOffsetAPI_ThruSections loft(Standard_False /*shell, no end caps*/,
ruled ? Standard_True : Standard_False);
BRepOffsetAPI_ThruSections loft(false /*shell, no end caps*/, ruled);
for (const TopoDS_Wire& w : profiles) {
if (w.IsNull()) throw std::runtime_error("loft: null profile wire");
loft.AddWire(w);
@@ -597,15 +595,15 @@ std::vector<TopoDS_Wire> SketchEngine::entities_to_wires(const std::vector<Sketc
const int n = int(c.ctrl.size());
const int p = n >= 4 ? 3 : (n >= 2 ? n - 1 : 0);
if (p < 1) return Handle(Geom_BSplineCurve)();
TColgp_Array1OfPnt poles(1, n);
NCollection_Array1<gp_Pnt> poles(1, n);
for (int i = 0; i < n; ++i) {
Vec3d w = plane.to_world(c.ctrl[i]);
poles.SetValue(i + 1, gp_Pnt(w.x(), w.y(), w.z()));
}
const int interior = n - p - 1; // count of single interior knots
const int nknots = interior + 2;
TColStd_Array1OfReal knots(1, nknots);
TColStd_Array1OfInteger mults(1, nknots);
NCollection_Array1<double> knots(1, nknots);
NCollection_Array1<int> mults(1, nknots);
knots.SetValue(1, 0.0); mults.SetValue(1, p + 1);
for (int i = 1; i <= interior; ++i) { knots.SetValue(i + 1, double(i)); mults.SetValue(i + 1, 1); }
knots.SetValue(nknots, double(interior + 1)); mults.SetValue(nknots, p + 1);
@@ -808,7 +806,7 @@ std::vector<TopoDS_Wire> SketchEngine::entities_to_wires(const std::vector<Sketc
wm.Add(BRepBuilderAPI_MakeEdge(va, vb).Edge());
} else if (e->type == SketchEntity::Type::EllipseArc) {
if (e->radius <= 1e-9 || e->rminor <= 1e-9) return {};
GC_MakeArcOfEllipse arc_maker(make_elips(*e), e->start_angle, e->end_angle, Standard_True);
GC_MakeArcOfEllipse arc_maker(make_elips(*e), e->start_angle, e->end_angle, true);
if (!arc_maker.IsDone()) return {};
wm.Add(BRepBuilderAPI_MakeEdge(arc_maker.Value(), va, vb).Edge());
} else if (e->type == SketchEntity::Type::Arc) {
+3
View File
@@ -7,6 +7,7 @@
#include <gp_Pln.hxx>
#include <gp_Ax3.hxx>
#include <gp_Vec.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Face.hxx>
@@ -227,6 +228,8 @@ struct SketchParams {
class SketchEngine
{
public:
// Throws on a zero vector, for which OCCT returns a degenerate solid.
static TopoDS_Shape make_prism(const TopoDS_Shape& base, const gp_Vec& vec);
static TopoDS_Shape make_extrude(const TopoDS_Wire& wire, const SketchPlane& plane,
double length, bool symmetric = false, double taper_deg = 0.0);
static TopoDS_Shape make_extrude(const TopoDS_Face& face, const SketchPlane& plane,
+24 -5
View File
@@ -648,11 +648,8 @@ find_package(JPEG REQUIRED)
find_package(Draco REQUIRED)
set(OCCT_LIBS
TKXDESTEP
TKSTEP
TKSTEP209
TKSTEPAttr
TKSTEPBase
TKDESTEP
TKDE
TKXCAF
TKXSBase
TKVCAF
@@ -699,6 +696,22 @@ if (SLIC3R_CAD)
endif ()
# Published for the Windows packaging step in the top-level CMakeLists.txt.
set(OCCT_LIBS "${OCCT_LIBS}" CACHE INTERNAL "OCCT toolkits linked by libslic3r")
if (WIN32)
# OCCT installs RelWithDebInfo and Debug builds to bin/occti and bin/occtd, so each build
# type's DLL directory is read from the imported target, falling back to the first installed
# build, as CMake does when linking.
get_target_property(_occt_configs TKernel IMPORTED_CONFIGURATIONS)
list(GET _occt_configs 0 _occt_fallback)
foreach (_build_config IN ITEMS DEBUG RELEASE RELWITHDEBINFO MINSIZEREL)
set(_occt_config ${_occt_fallback})
if (_build_config IN_LIST _occt_configs)
set(_occt_config ${_build_config})
endif ()
get_target_property(_occt_dll TKernel IMPORTED_LOCATION_${_occt_config})
get_filename_component(_occt_bin "${_occt_dll}" DIRECTORY)
set(OCCT_BIN_DIR_${_build_config} "${_occt_bin}" CACHE INTERNAL "OCCT DLL directory for ${_build_config} builds")
endforeach ()
endif ()
target_link_libraries(libslic3r
PUBLIC
@@ -733,6 +746,12 @@ target_link_libraries(libslic3r
)
if(NOT WIN32)
# OCCT's static targets name FreeType as a bare "freetype", which the macOS linker cannot
# find; this target maps that name to FREETYPE_LIBRARIES.
if (NOT TARGET freetype)
add_library(freetype INTERFACE IMPORTED GLOBAL)
target_link_libraries(freetype INTERFACE ${FREETYPE_LIBRARIES})
endif ()
# Link freetype for OCCT dependency (CAD operations need font rendering)
target_link_libraries(libslic3r PRIVATE ${FREETYPE_LIBRARIES})
if (NOT APPLE)
+17 -16
View File
@@ -47,7 +47,8 @@
#include "XCAFDoc_DocumentTool.hxx"
#include "XCAFDoc_ShapeTool.hxx"
#include "XCAFApp_Application.hxx"
#include "TDF_LabelSequence.hxx"
#include "NCollection_Sequence.hxx"
#include "TDF_Label.hxx"
#include "TopoDS_Solid.hxx"
#include "TopoDS_Compound.hxx"
#include "TopoDS_Builder.hxx"
@@ -223,9 +224,9 @@ static void getNamedSolids(const TopLoc_Location& location,
std::string fullName{name};
TopLoc_Location localLocation = location * shapeTool->GetLocation(label);
TDF_LabelSequence components;
NCollection_Sequence<TDF_Label> components;
if (shapeTool->GetComponents(referredLabel, components)) {
for (Standard_Integer compIndex = 1; compIndex <= components.Length(); ++compIndex) {
for (int compIndex = 1; compIndex <= components.Length(); ++compIndex) {
getNamedSolids(localLocation, fullName, id, shapeTool, components.Value(compIndex), namedSolids, isSplitCompound);
}
} else {
@@ -233,7 +234,7 @@ static void getNamedSolids(const TopLoc_Location& location,
TopExp_Explorer explorer;
shapeTool->GetShape(referredLabel, shape);
TopAbs_ShapeEnum shape_type = shape.ShapeType();
BRepBuilderAPI_Transform transform(shape, localLocation, Standard_True);
BRepBuilderAPI_Transform transform(shape, localLocation, true);
int i = 0;
switch (shape_type) {
case TopAbs_COMPOUND:
@@ -503,11 +504,11 @@ Step::Step_Status Step::load()
if (cb_cancel) return;
progress = 6;
m_shape_tool = XCAFDoc_DocumentTool::ShapeTool(m_doc->Main());
TDF_LabelSequence topLevelShapes;
NCollection_Sequence<TDF_Label> topLevelShapes;
m_shape_tool->GetFreeShapes(topLevelShapes);
unsigned int id{ 1 };
Standard_Integer topShapeLength = topLevelShapes.Length() + 1;
for (Standard_Integer iLabel = 1; iLabel < topShapeLength; ++iLabel) {
int topShapeLength = topLevelShapes.Length() + 1;
for (int iLabel = 1; iLabel < topShapeLength; ++iLabel) {
if (cb_cancel) return;
getNamedSolids(TopLoc_Location{}, "", id, m_shape_tool, topLevelShapes.Value(iLabel), m_name_solids);
}
@@ -562,12 +563,12 @@ Step::Step_Status Step::mesh(Model* model,
new_object->input_file = m_path.c_str();
auto task = new boost::thread(Slic3r::create_thread([&]() -> void {
TDF_LabelSequence topLevelShapes;
NCollection_Sequence<TDF_Label> topLevelShapes;
m_shape_tool->GetFreeShapes(topLevelShapes);
unsigned int id{ 1 };
Standard_Integer topShapeLength = topLevelShapes.Length() + 1;
int topShapeLength = topLevelShapes.Length() + 1;
for (Standard_Integer iLabel = 1; iLabel < topShapeLength; ++iLabel) {
for (int iLabel = 1; iLabel < topShapeLength; ++iLabel) {
progress = static_cast<double>(iLabel) / (topShapeLength-1);
if (cb_cancel) {
return;
@@ -604,10 +605,10 @@ Step::Step_Status Step::mesh(Model* model,
std::vector<Vec3f> points;
points.reserve(aNbNodes);
// BBS: count faces missing triangulation
Standard_Integer aNbFacesNoTri = 0;
int aNbFacesNoTri = 0;
// BBS: fill temporary triangulation
Standard_Integer aNodeOffset = 0;
Standard_Integer aTriangleOffet = 0;
int aNodeOffset = 0;
int aTriangleOffet = 0;
for (TopExp_Explorer anExpSF(namedSolids[i].solid, TopAbs_FACE); anExpSF.More(); anExpSF.Next()) {
const TopoDS_Shape& aFace = anExpSF.Current();
TopLoc_Location aLoc;
@@ -618,15 +619,15 @@ Step::Step_Status Step::mesh(Model* model,
}
// BBS: copy nodes
gp_Trsf aTrsf = aLoc.Transformation();
for (Standard_Integer aNodeIter = 1; aNodeIter <= aTriangulation->NbNodes(); ++aNodeIter) {
for (int aNodeIter = 1; aNodeIter <= aTriangulation->NbNodes(); ++aNodeIter) {
gp_Pnt aPnt = aTriangulation->Node(aNodeIter);
aPnt.Transform(aTrsf);
points.emplace_back(Vec3f(aPnt.X(), aPnt.Y(), aPnt.Z()));
}
// BBS: copy triangles
const TopAbs_Orientation anOrientation = anExpSF.Current().Orientation();
Standard_Integer anId[3] = {};
for (Standard_Integer aTriIter = 1; aTriIter <= aTriangulation->NbTriangles(); ++aTriIter) {
int anId[3] = {};
for (int aTriIter = 1; aTriIter <= aTriangulation->NbTriangles(); ++aTriIter) {
Poly_Triangle aTri = aTriangulation->Triangle(aTriIter);
aTri.Get(anId[0], anId[1], anId[2]);
+2 -2
View File
@@ -84,9 +84,9 @@ class StepProgressIncdicator : public Message_ProgressIndicator
public:
StepProgressIncdicator(std::atomic<bool>& stop_flag) : should_stop(stop_flag){}
Standard_Boolean UserBreak() override { return should_stop.load(); }
bool UserBreak() override { return should_stop.load(); }
void Show(const Message_ProgressScope&, const Standard_Boolean) override {
void Show(const Message_ProgressScope&, const bool) override {
std::cout << "Progress: " << std::fixed << std::setprecision(2) << 100.0 * GetPosition() << "%" << std::endl;
}
private:
+6 -6
View File
@@ -339,10 +339,10 @@ bool load_svg(const char *path, Model *model, std::string &message)
std::vector<Vec3f> points;
points.reserve(aNbNodes);
// BBS: count faces missing triangulation
Standard_Integer aNbFacesNoTri = 0;
int aNbFacesNoTri = 0;
// BBS: fill temporary triangulation
Standard_Integer aNodeOffset = 0;
Standard_Integer aTriangleOffet = 0;
int aNodeOffset = 0;
int aTriangleOffet = 0;
for (TopExp_Explorer anExpSF(namedSolids[i].shape, TopAbs_FACE); anExpSF.More(); anExpSF.Next()) {
const TopoDS_Shape &aFace = anExpSF.Current();
TopLoc_Location aLoc;
@@ -353,15 +353,15 @@ bool load_svg(const char *path, Model *model, std::string &message)
}
// BBS: copy nodes
gp_Trsf aTrsf = aLoc.Transformation();
for (Standard_Integer aNodeIter = 1; aNodeIter <= aTriangulation->NbNodes(); ++aNodeIter) {
for (int aNodeIter = 1; aNodeIter <= aTriangulation->NbNodes(); ++aNodeIter) {
gp_Pnt aPnt = aTriangulation->Node(aNodeIter);
aPnt.Transform(aTrsf);
points.emplace_back(Vec3f(aPnt.X(), aPnt.Y(), aPnt.Z()));
}
// BBS: copy triangles
const TopAbs_Orientation anOrientation = anExpSF.Current().Orientation();
Standard_Integer anId[3];
for (Standard_Integer aTriIter = 1; aTriIter <= aTriangulation->NbTriangles(); ++aTriIter) {
int anId[3];
for (int aTriIter = 1; aTriIter <= aTriangulation->NbTriangles(); ++aTriIter) {
Poly_Triangle aTri = aTriangulation->Triangle(aTriIter);
aTri.Get(anId[0], anId[1], anId[2]);
+20 -20
View File
@@ -50,6 +50,8 @@
#include "Font_BRepTextBuilder.hxx"
#include "BRepPrimAPI_MakePrism.hxx"
#include "Font_FontMgr.hxx"
#include "NCollection_Sequence.hxx"
#include "TCollection_HAsciiString.hxx"
#include <boost/log/trivial.hpp>
@@ -57,7 +59,7 @@ namespace Slic3r {
static std::map<std::string, std::string> g_occt_fonts_maps; //map<font_name, font_path>
static const std::vector<Standard_CString> fonts_suffix{ "Bold", "Medium", "Heavy", "Italic", "Oblique", "Inclined", "Light", "Thin",
static const std::vector<const char*> fonts_suffix{ "Bold", "Medium", "Heavy", "Italic", "Oblique", "Inclined", "Light", "Thin",
"Semibold", "ExtraBold", "ExtraBold", "Semilight", "SemiLight", "ExtraLight", "Extralight", "Ultralight",
"Condensed", "Ultra", "Extra", "Expanded", "Extended", "1", "2", "3", "4", "5", "6", "7", "8", "9", "Al Tarikh"};
@@ -73,7 +75,7 @@ std::vector<std::string> init_occt_fonts()
Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance();
aFontMgr->InitFontDataBase();
TColStd_SequenceOfHAsciiString availFontNames;
NCollection_Sequence<Handle(TCollection_HAsciiString)> availFontNames;
aFontMgr->GetAvailableFontsNames(availFontNames);
stdFontNames.reserve(availFontNames.Size());
@@ -122,16 +124,14 @@ std::vector<std::string> init_occt_fonts()
static bool TextToBRep(const char* text, const char* font, const float theTextHeight, Font_FontAspect& theFontAspect, TopoDS_Shape& theShape, double& text_width)
{
Standard_Integer anArgIt = 1;
Standard_CString aName = "text_shape";
Standard_CString aText = text;
const char* aText = text;
Font_BRepFont aFont;
//TCollection_AsciiString aFontName("Courier");
TCollection_AsciiString aFontName(font);
Standard_Real aTextHeight = theTextHeight;
double aTextHeight = theTextHeight;
Font_FontAspect aFontAspect = theFontAspect;
Standard_Boolean anIsCompositeCurve = Standard_False;
bool anIsCompositeCurve = false;
gp_Ax3 aPenAx3(gp::XOY());
gp_Dir aNormal(0.0, 0.0, 1.0);
gp_Dir aDirection(1.0, 0.0, 0.0);
@@ -156,10 +156,10 @@ static bool TextToBRep(const char* text, const char* font, const float theTextHe
// get the text width
text_width = 0;
NCollection_String coll_str = aText;
for (NCollection_Utf8Iter anIter = coll_str.Iterator(); *anIter != 0;) {
const Standard_Utf32Char aCharThis = *anIter;
const Standard_Utf32Char aCharNext = *++anIter;
double width = aFont.AdvanceX(aCharThis, aCharNext);
for (auto anIter = coll_str.Iterator(); *anIter != 0;) {
const char32_t aCharThis = *anIter;
const char32_t aCharNext = *++anIter;
double width = aFont.AdvanceX(aCharThis, aCharNext);
text_width += width;
}
@@ -173,9 +173,9 @@ static bool Prism(const TopoDS_Shape& theBase, const float thickness, TopoDS_Sha
if (theBase.IsNull()) return false;
gp_Vec V(0.f, 0.f, thickness);
BRepPrimAPI_MakePrism* Prism = new BRepPrimAPI_MakePrism(theBase, V, Standard_False);
BRepPrimAPI_MakePrism prism(theBase, V, false);
theSolid = Prism->Shape();
theSolid = prism.Shape();
return true;
}
@@ -205,10 +205,10 @@ static void MakeMesh(TopoDS_Shape& theSolid, TriangleMesh& theMesh)
std::vector<Vec3f> points;
points.reserve(aNbNodes);
//BBS: count faces missing triangulation
Standard_Integer aNbFacesNoTri = 0;
int aNbFacesNoTri = 0;
//BBS: fill temporary triangulation
Standard_Integer aNodeOffset = 0;
Standard_Integer aTriangleOffet = 0;
int aNodeOffset = 0;
int aTriangleOffet = 0;
for (TopExp_Explorer anExpSF(theSolid, TopAbs_FACE); anExpSF.More(); anExpSF.Next()) {
const TopoDS_Shape& aFace = anExpSF.Current();
TopLoc_Location aLoc;
@@ -219,21 +219,21 @@ static void MakeMesh(TopoDS_Shape& theSolid, TriangleMesh& theMesh)
}
//BBS: copy nodes
gp_Trsf aTrsf = aLoc.Transformation();
for (Standard_Integer aNodeIter = 1; aNodeIter <= aTriangulation->NbNodes(); ++aNodeIter) {
for (int aNodeIter = 1; aNodeIter <= aTriangulation->NbNodes(); ++aNodeIter) {
gp_Pnt aPnt = aTriangulation->Node(aNodeIter);
aPnt.Transform(aTrsf);
points.emplace_back(Vec3f(aPnt.X(), aPnt.Y(), aPnt.Z()));
}
//BBS: copy triangles
const TopAbs_Orientation anOrientation = anExpSF.Current().Orientation();
for (Standard_Integer aTriIter = 1; aTriIter <= aTriangulation->NbTriangles(); ++aTriIter) {
for (int aTriIter = 1; aTriIter <= aTriangulation->NbTriangles(); ++aTriIter) {
Poly_Triangle aTri = aTriangulation->Triangle(aTriIter);
Standard_Integer anId[3];
int anId[3];
aTri.Get(anId[0], anId[1], anId[2]);
if (anOrientation == TopAbs_REVERSED) {
//BBS: swap 1, 2.
Standard_Integer aTmpIdx = anId[1];
int aTmpIdx = anId[1];
anId[1] = anId[2];
anId[2] = aTmpIdx;
}
+6 -24
View File
@@ -16,7 +16,6 @@
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/log/trivial.hpp> // the offer/atlas join check reports on the log
#include <Standard_Failure.hxx>
#include <cassert>
#include <cstdarg> // offer_trace: diagnostic row dump for the offer ladder
@@ -4694,7 +4693,7 @@ void DesignPanel::on_import_svg()
// (parse + tessellate); running it inline froze the whole window — the compositor marked the
// app unresponsive and nothing repainted. The dialog is app-modal, so the document cannot be
// touched while the worker owns it. Exceptions must not escape the worker: `work` is expected
// to swallow them (OCCT throws Standard_Failure, which is not a std::exception).
// to swallow them.
static void run_off_ui_thread(wxWindow* parent, const wxString& message, const std::function<void()>& work)
{
std::atomic<bool> done{false};
@@ -4722,10 +4721,6 @@ static void run_off_ui_thread(wxWindow* parent, const wxString& message, const s
worker.join();
}
// Rebuild the document off the UI thread. Every feature op (fillet, cut, shell, boolean, ...)
// goes through recompute(), and on a heavy imported solid that is seconds of OCCT work — inline
// it freezes the window. OCCT throws Standard_Failure, which is not a std::exception and would
// terminate the process if it escaped the worker, so both are caught here.
// Keep the Model's copy of the recipe in step with the document.
//
// This used to be written in exactly ONE place — on_commit(), as a side effect of Commit to
@@ -4756,18 +4751,15 @@ void DesignPanel::sync_recipe_to_model()
Slic3r::put_other_changes();
}
// Runs recompute() off the UI thread, because on a heavy imported solid it takes seconds.
bool DesignPanel::recompute_guarded(const wxString& message)
{
bool ok = false;
run_off_ui_thread(this, message, [this, &ok]() {
try {
ok = m_doc.recompute();
} catch (const Standard_Failure& e) {
const char* what = e.GetMessageString();
m_doc.error = (what != nullptr && *what != '\0') ? what : "OCCT failure";
ok = false;
} catch (const std::exception& e) {
m_doc.error = e.what();
m_doc.error = *e.what() ? e.what() : "OCCT failure";
ok = false;
}
});
@@ -4792,11 +4784,8 @@ void DesignPanel::on_import_step()
run_off_ui_thread(this, _L("Reading STEP…"), [&]() {
try {
solids = GeometryEngine::read_step_solids(path, err);
} catch (const Standard_Failure& e) {
const char* what = e.GetMessageString();
err = (what != nullptr && *what != '\0') ? what : "OCCT failure";
} catch (const std::exception& e) {
err = e.what();
err = *e.what() ? e.what() : "OCCT failure";
}
});
if (solids.empty()) {
@@ -4820,11 +4809,8 @@ void DesignPanel::on_import_step()
run_off_ui_thread(this, _L("Rebuilding model…"), [&]() {
try {
rebuilt = m_doc.recompute();
} catch (const Standard_Failure& e) {
const char* what = e.GetMessageString();
m_doc.error = (what != nullptr && *what != '\0') ? what : "OCCT failure";
} catch (const std::exception& e) {
m_doc.error = e.what();
m_doc.error = *e.what() ? e.what() : "OCCT failure";
}
});
if (!rebuilt) {
@@ -4901,12 +4887,8 @@ void DesignPanel::on_import_mesh()
try {
shape = GeometryEngine::mesh_to_brep(mesh.its, MESH_IMPORT_TOLERANCE,
MESH_IMPORT_MERGE_ANGLE_DEG, stats);
} catch (const Standard_Failure& e) { // on OCCT >= 8 Standard_Failure derives from std::exception — must precede that handler
fail(_L("Mesh conversion failed: ") + wxString::FromUTF8(
e.GetMessageString() ? e.GetMessageString() : "OCCT error"));
return;
} catch (const std::exception& e) {
fail(_L("Mesh conversion failed: ") + wxString::FromUTF8(e.what()));
fail(_L("Mesh conversion failed: ") + wxString::FromUTF8(*e.what() ? e.what() : "OCCT error"));
return;
}
if (shape.IsNull()) { fail(_L("Mesh conversion produced no geometry")); return; }
+7 -7
View File
@@ -27,7 +27,7 @@
#include <nlohmann/json.hpp>
#include <boost/log/trivial.hpp>
#include <Standard_Failure.hxx> // OCCT base error (not a std::exception)
#include <Standard_Failure.hxx> // OCCT base error
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/MainFrame.hpp"
@@ -637,9 +637,9 @@ json slice_body(DesignPanel* panel, const json& params)
: plane_name == "YZ" ? gp_Dir(1, 0, 0)
: gp_Dir(0, 0, 1);
gp_Pnt o(n.X() * offset, n.Y() * offset, n.Z() * offset);
BRepAlgoAPI_Section sect(shape, gp_Pln(o, n), Standard_False);
sect.ComputePCurveOn1(Standard_False);
sect.Approximation(Standard_True);
BRepAlgoAPI_Section sect(shape, gp_Pln(o, n), false);
sect.ComputePCurveOn1(false);
sect.Approximation(true);
sect.Build();
if (!sect.IsDone()) throw std::runtime_error("section failed");
std::vector<std::vector<Vec3d>> segs;
@@ -751,7 +751,7 @@ ShapeMetrics shape_metrics(const TopoDS_Shape& s)
GProp_GProps vp; BRepGProp::VolumeProperties(s, vp);
gp_Pnt c = vp.CentreOfMass();
Bnd_Box bb; BRepBndLib::Add(s, bb);
Standard_Real x0, y0, z0, x1, y1, z1; bb.Get(x0, y0, z0, x1, y1, z1);
double x0, y0, z0, x1, y1, z1; bb.Get(x0, y0, z0, x1, y1, z1);
return {vp.Mass(), Vec3d(c.X(), c.Y(), c.Z()), Vec3d(x0, y0, z0), Vec3d(x1, y1, z1)};
}
@@ -2095,8 +2095,8 @@ std::string handle_on_main(const std::string& method, const json& params, const
if (method == "mate") return rpc_result(id, action_mate(panel, params));
if (method == "check_interference") return rpc_result(id, action_check_interference(panel, params));
return rpc_error(id, -32601, "Unknown method: " + method);
} catch (const Standard_Failure& ex) { // OCCT errors are NOT std::exception
return rpc_error(id, -32000, std::string("OCCT: ") + (ex.GetMessageString() ? ex.GetMessageString() : "failure"));
} catch (const Standard_Failure& ex) { // derives from std::exception, so it comes first
return rpc_error(id, -32000, std::string("OCCT: ") + (*ex.what() ? ex.what() : "failure"));
} catch (const std::exception& ex) {
return rpc_error(id, -32000, ex.what());
}
+1 -1
View File
@@ -827,7 +827,7 @@ indexed_triangle_set GLGizmoCut3D::its_make_groove_plane()
float slot_mouth_outer_x = slot_neck_half_width + flap_taper_offset; // upper_x extension
float slot_neck_outer_x = slot_mouth_half_width + flap_taper_offset; // lower_x extension
float slot_outer_x_max = Max(slot_neck_outer_x, slot_mouth_outer_x); // max x extension
float slot_outer_x_max = std::max(slot_neck_outer_x, slot_mouth_outer_x); // max x extension
float slot_neck_inner_x = slot_neck_half_width - flap_taper_offset; // upper_x narrowing
float slot_mouth_inner_x = slot_mouth_half_width - flap_taper_offset; // lower_x narrowing