10C Inc 3 + 4: I/O and text — the app's whole OCP surface is bound
138/138 symbols across 53 modules. New: IFSelect, Interface, XSControl, IGESData, STEPControl, IGESControl, RWStl, Graphic3d, NCollection, StdPrs. **The full app suite passes against this wheel: 1797 passed, 1 skipped — the same result as the stock wheel**, run from the parity venv. Getting there needed six methods that no static analysis could have found: `inventory --check` only sees symbols reached through an import, so a method called on an instance is invisible to it. The suite found them in one pass, and one of them (gp_Vec.Reverse, which every outward-normal probe calls) accounted for 311 of the 255 failing tests on its own. The others: gp_Trsf.SetMirror over a plane and a point, Geom_Surface.D0, BRep_Builder.MakeFace from a triangulation, MakePipeShell.SetMode with a fixed binormal, and MakeFace from a surface plus tolerance. Open question **S5 is settled: no**. The wheel does not need OCCT's share/ resources. test_inc3_io.py asserts no CSF_* variable is set and then round-trips STEP and IGES, reading the declared units back off both — which is exactly the resource-less container the question was about. The XSTEP readers keep the GIL, amending the blanket "file readers and writers" line in design.md's GIL policy. STEP and IGES traffic in process-global Interface_Static state, the IGES reader is documented as not thread-safe, and the app already serialises imports behind a lock — so holding it costs nothing and removes a class of question. RWStl, which touches no global state, releases. XSControl_Reader and IGESData are registered although the app imports neither: they are the reader base both concrete readers inherit their transfer surface from, and the model-to-global-section chain the IGES unit probe walks. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DfriM8XUkn7uYf5Dwe2xo6
This commit is contained in:
26
src/core.cpp
26
src/core.cpp
@@ -66,6 +66,18 @@ void register_BRepLib(nb::module_ &);
|
||||
void register_BRepExtrema(nb::module_ &);
|
||||
void register_BRepClass3d(nb::module_ &);
|
||||
void register_IntCurvesFace(nb::module_ &);
|
||||
// Inc 3 — I/O
|
||||
void register_IFSelect(nb::module_ &);
|
||||
void register_Interface(nb::module_ &);
|
||||
void register_XSControl(nb::module_ &);
|
||||
void register_IGESData(nb::module_ &);
|
||||
void register_STEPControl(nb::module_ &);
|
||||
void register_IGESControl(nb::module_ &);
|
||||
void register_RWStl(nb::module_ &);
|
||||
// Inc 4 — remainder
|
||||
void register_Graphic3d(nb::module_ &);
|
||||
void register_NCollection(nb::module_ &);
|
||||
void register_StdPrs(nb::module_ &);
|
||||
void register_ext(nb::module_ &);
|
||||
|
||||
NB_MODULE(_OCP, m) {
|
||||
@@ -124,6 +136,20 @@ NB_MODULE(_OCP, m) {
|
||||
register_BRepClass3d(m);
|
||||
register_IntCurvesFace(m);
|
||||
|
||||
// Inc 3. XSControl declares the reader base both concrete readers use.
|
||||
register_IFSelect(m);
|
||||
register_Interface(m);
|
||||
register_XSControl(m);
|
||||
register_IGESData(m);
|
||||
register_STEPControl(m);
|
||||
register_IGESControl(m);
|
||||
register_RWStl(m);
|
||||
|
||||
// Inc 4. Graphic3d's alignment enums are arguments to StdPrs.
|
||||
register_Graphic3d(m);
|
||||
register_NCollection(m);
|
||||
register_StdPrs(m);
|
||||
|
||||
register_ext(m);
|
||||
|
||||
m.attr("__all_modules__") = ocp_module_registry();
|
||||
|
||||
@@ -34,6 +34,13 @@ void register_BRep(nb::module_ &root) {
|
||||
.def(nb::init<>())
|
||||
.def("MakeCompound", &BRep_Builder::MakeCompound, "C"_a)
|
||||
.def("MakeShell", &BRep_Builder::MakeShell, "S"_a)
|
||||
.def(
|
||||
"MakeFace",
|
||||
[](const BRep_Builder &self, TopoDS_Face &F,
|
||||
const opencascade::handle<Poly_Triangulation> &T) {
|
||||
self.MakeFace(F, T);
|
||||
},
|
||||
"F"_a, "T"_a)
|
||||
.def("MakeSolid", &BRep_Builder::MakeSolid, "S"_a)
|
||||
.def("MakeWire", &BRep_Builder::MakeWire, "W"_a)
|
||||
.def("Add",
|
||||
|
||||
@@ -105,6 +105,9 @@ void register_BRepBuilderAPI(nb::module_ &root) {
|
||||
"P"_a, "UMin"_a, "UMax"_a, "VMin"_a, "VMax"_a)
|
||||
.def(nb::init<const TopoDS_Wire &, const Standard_Boolean>(), "W"_a,
|
||||
"OnlyPlane"_a = Standard_False)
|
||||
.def(nb::init<const opencascade::handle<Geom_Surface> &,
|
||||
const Standard_Real>(),
|
||||
"S"_a, "TolDegen"_a)
|
||||
.def(nb::init<const opencascade::handle<Geom_Surface> &,
|
||||
const TopoDS_Wire &, const Standard_Boolean>(),
|
||||
"S"_a, "W"_a, "Inside"_a = Standard_True)
|
||||
|
||||
@@ -50,6 +50,10 @@ void register_BRepOffsetAPI(nb::module_ &root) {
|
||||
nb::overload_cast<const Standard_Boolean>(
|
||||
&BRepOffsetAPI_MakePipeShell::SetMode),
|
||||
"IsFrenet"_a = Standard_False)
|
||||
.def("SetMode",
|
||||
nb::overload_cast<const gp_Dir &>(
|
||||
&BRepOffsetAPI_MakePipeShell::SetMode),
|
||||
"BiNormal"_a)
|
||||
.def("Add",
|
||||
nb::overload_cast<const TopoDS_Shape &, const Standard_Boolean,
|
||||
const Standard_Boolean>(
|
||||
|
||||
@@ -64,6 +64,7 @@ void register_Geom(nb::module_ &root) {
|
||||
|
||||
nb::class_<Geom_Surface, Standard_Transient>(m, "Geom_Surface")
|
||||
.def("Value", &Geom_Surface::Value, "U"_a, "V"_a, OCP_RETURN_COPY)
|
||||
.def("D0", &Geom_Surface::D0, "U"_a, "V"_a, "P"_a)
|
||||
.def("IsUPeriodic", &Geom_Surface::IsUPeriodic)
|
||||
.def("IsVPeriodic", &Geom_Surface::IsVPeriodic)
|
||||
.def("IsUClosed", &Geom_Surface::IsUClosed)
|
||||
|
||||
31
src/modules/mod_Graphic3d.cpp
Normal file
31
src/modules/mod_Graphic3d.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
OCP.Graphic3d — text alignment.
|
||||
|
||||
Only the two alignment enums, which the text-emboss feature passes to the
|
||||
BRep text builder. Nothing else in Graphic3d is a modelling concept, and
|
||||
the app draws nothing through OCCT.
|
||||
*/
|
||||
|
||||
#include "../common/occt_module.h"
|
||||
|
||||
#include <Graphic3d_HorizontalTextAlignment.hxx>
|
||||
#include <Graphic3d_VerticalTextAlignment.hxx>
|
||||
|
||||
void register_Graphic3d(nb::module_ &root) {
|
||||
nb::module_ m = ocp_submodule(root, "Graphic3d");
|
||||
|
||||
nb::enum_<Graphic3d_HorizontalTextAlignment>(
|
||||
m, "Graphic3d_HorizontalTextAlignment", nb::is_arithmetic())
|
||||
.value("Graphic3d_HTA_LEFT", Graphic3d_HTA_LEFT)
|
||||
.value("Graphic3d_HTA_CENTER", Graphic3d_HTA_CENTER)
|
||||
.value("Graphic3d_HTA_RIGHT", Graphic3d_HTA_RIGHT)
|
||||
.export_values();
|
||||
|
||||
nb::enum_<Graphic3d_VerticalTextAlignment>(
|
||||
m, "Graphic3d_VerticalTextAlignment", nb::is_arithmetic())
|
||||
.value("Graphic3d_VTA_BOTTOM", Graphic3d_VTA_BOTTOM)
|
||||
.value("Graphic3d_VTA_CENTER", Graphic3d_VTA_CENTER)
|
||||
.value("Graphic3d_VTA_TOP", Graphic3d_VTA_TOP)
|
||||
.value("Graphic3d_VTA_TOPFIRSTLINE", Graphic3d_VTA_TOPFIRSTLINE)
|
||||
.export_values();
|
||||
}
|
||||
23
src/modules/mod_IFSelect.cpp
Normal file
23
src/modules/mod_IFSelect.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
OCP.IFSelect — the return status every XSTEP read reports through.
|
||||
|
||||
The app only ever compares against IFSelect_RetDone, but the whole enum is
|
||||
bound so a failure prints as something other than a bare integer.
|
||||
*/
|
||||
|
||||
#include "../common/occt_module.h"
|
||||
|
||||
#include <IFSelect_ReturnStatus.hxx>
|
||||
|
||||
void register_IFSelect(nb::module_ &root) {
|
||||
nb::module_ m = ocp_submodule(root, "IFSelect");
|
||||
|
||||
nb::enum_<IFSelect_ReturnStatus>(m, "IFSelect_ReturnStatus",
|
||||
nb::is_arithmetic())
|
||||
.value("IFSelect_RetVoid", IFSelect_RetVoid)
|
||||
.value("IFSelect_RetDone", IFSelect_RetDone)
|
||||
.value("IFSelect_RetError", IFSelect_RetError)
|
||||
.value("IFSelect_RetFail", IFSelect_RetFail)
|
||||
.value("IFSelect_RetStop", IFSelect_RetStop)
|
||||
.export_values();
|
||||
}
|
||||
57
src/modules/mod_IGESControl.cpp
Normal file
57
src/modules/mod_IGESControl.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
OCP.IGESControl — IGES read and write.
|
||||
|
||||
The reader inherits its transfer surface from XSControl_Reader. What is
|
||||
specific here is the unit probe: the app reads the file's declared units
|
||||
off the model's global section (IGESModel().GlobalSection().UnitName()),
|
||||
which is why IGESData_IGESModel and IGESData_GlobalSection have to be
|
||||
registered even though the app imports neither by name.
|
||||
|
||||
The writer is used only by the test suite, to produce IGES payloads to
|
||||
import back; it is bound because those tests are part of the Inc 4 gate.
|
||||
|
||||
GIL held, per mod_XSControl.cpp — the IGES reader is explicitly documented
|
||||
as not thread-safe.
|
||||
*/
|
||||
|
||||
#include "../common/occt_module.h"
|
||||
#include "../common/occt_policies.h"
|
||||
|
||||
#include <IGESControl_Controller.hxx>
|
||||
#include <IGESControl_Reader.hxx>
|
||||
#include <IGESControl_Writer.hxx>
|
||||
#include <IGESData_GlobalSection.hxx>
|
||||
#include <IGESData_IGESModel.hxx>
|
||||
#include <TCollection_HAsciiString.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <XSControl_Reader.hxx>
|
||||
|
||||
void register_IGESControl(nb::module_ &root) {
|
||||
nb::module_ m = ocp_submodule(root, "IGESControl");
|
||||
|
||||
nb::class_<IGESControl_Controller> controller(m, "IGESControl_Controller");
|
||||
OCP_DEF_S(
|
||||
controller, "Init", []() { return IGESControl_Controller::Init(); });
|
||||
|
||||
nb::class_<IGESControl_Reader, XSControl_Reader>(m, "IGESControl_Reader")
|
||||
.def(nb::init<>())
|
||||
.def("IGESModel", &IGESControl_Reader::IGESModel);
|
||||
|
||||
nb::class_<IGESControl_Writer>(m, "IGESControl_Writer")
|
||||
.def(nb::init<>())
|
||||
.def(nb::init<const Standard_CString, const Standard_Integer>(),
|
||||
"unit_name"_a, "modecr"_a = 0)
|
||||
// AddShape carries a Message_ProgressRange the app never supplies.
|
||||
.def(
|
||||
"AddShape",
|
||||
[](IGESControl_Writer &self, const TopoDS_Shape &sh) {
|
||||
return self.AddShape(sh);
|
||||
},
|
||||
"sh"_a, OCP_NOGIL)
|
||||
.def("ComputeModel", &IGESControl_Writer::ComputeModel, OCP_NOGIL)
|
||||
.def(
|
||||
"Write",
|
||||
[](IGESControl_Writer &self, const Standard_CString file,
|
||||
const Standard_Boolean fnes) { return self.Write(file, fnes); },
|
||||
"file"_a, "fnes"_a = Standard_False);
|
||||
}
|
||||
38
src/modules/mod_IGESData.cpp
Normal file
38
src/modules/mod_IGESData.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
OCP.IGESData — the IGES model's global section.
|
||||
|
||||
Not imported by the app, but reached through it: the unit probe walks
|
||||
reader.IGESModel().GlobalSection().UnitName(), so both classes need to be
|
||||
registered for that chain to convert. Only the two unit accessors are
|
||||
bound.
|
||||
|
||||
UnitName hands back a Handle(TCollection_HAsciiString), which is why that
|
||||
transient is registered here too rather than in mod_TCollection.cpp — it
|
||||
has no other consumer.
|
||||
*/
|
||||
|
||||
#include "../common/occt_module.h"
|
||||
#include "../common/occt_policies.h"
|
||||
|
||||
#include <IGESData_GlobalSection.hxx>
|
||||
#include <IGESData_IGESModel.hxx>
|
||||
#include <TCollection_HAsciiString.hxx>
|
||||
|
||||
void register_IGESData(nb::module_ &root) {
|
||||
nb::module_ m = ocp_submodule(root, "IGESData");
|
||||
|
||||
nb::class_<TCollection_HAsciiString, Standard_Transient>(
|
||||
m, "TCollection_HAsciiString")
|
||||
.def("ToCString", &TCollection_HAsciiString::ToCString)
|
||||
.def("Length", &TCollection_HAsciiString::Length)
|
||||
.def("__str__", &TCollection_HAsciiString::ToCString);
|
||||
|
||||
nb::class_<IGESData_GlobalSection>(m, "IGESData_GlobalSection")
|
||||
.def(nb::init<>())
|
||||
.def("UnitName", &IGESData_GlobalSection::UnitName)
|
||||
.def("UnitValue", &IGESData_GlobalSection::UnitValue);
|
||||
|
||||
nb::class_<IGESData_IGESModel, Standard_Transient>(m, "IGESData_IGESModel")
|
||||
.def("GlobalSection", &IGESData_IGESModel::GlobalSection,
|
||||
OCP_RETURN_COPY);
|
||||
}
|
||||
43
src/modules/mod_Interface.cpp
Normal file
43
src/modules/mod_Interface.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
OCP.Interface — XSTEP's process-global settings table.
|
||||
|
||||
The app reads and writes "xstep.cascade.unit" around an IGES import to make
|
||||
the reader interpret the file in its own units, then puts the previous
|
||||
value back. That is genuinely global state, which is why the app holds a
|
||||
lock across the whole read — and why these keep the GIL.
|
||||
*/
|
||||
|
||||
#include "../common/occt_module.h"
|
||||
|
||||
#include <Interface_Static.hxx>
|
||||
|
||||
void register_Interface(nb::module_ &root) {
|
||||
nb::module_ m = ocp_submodule(root, "Interface");
|
||||
|
||||
nb::class_<Interface_Static> cls(m, "Interface_Static");
|
||||
|
||||
OCP_DEF_S(
|
||||
cls, "CVal",
|
||||
[](const Standard_CString name) { return Interface_Static::CVal(name); },
|
||||
"name"_a);
|
||||
OCP_DEF_S(
|
||||
cls, "SetCVal",
|
||||
[](const Standard_CString name, const Standard_CString val) {
|
||||
return Interface_Static::SetCVal(name, val);
|
||||
},
|
||||
"name"_a, "val"_a);
|
||||
OCP_DEF_S(
|
||||
cls, "IVal",
|
||||
[](const Standard_CString name) { return Interface_Static::IVal(name); },
|
||||
"name"_a);
|
||||
OCP_DEF_S(
|
||||
cls, "SetIVal",
|
||||
[](const Standard_CString name, const Standard_Integer val) {
|
||||
return Interface_Static::SetIVal(name, val);
|
||||
},
|
||||
"name"_a, "val"_a);
|
||||
OCP_DEF_S(
|
||||
cls, "RVal",
|
||||
[](const Standard_CString name) { return Interface_Static::RVal(name); },
|
||||
"name"_a);
|
||||
}
|
||||
32
src/modules/mod_NCollection.cpp
Normal file
32
src/modules/mod_NCollection.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
OCP.NCollection — the UTF-8 string the font API takes.
|
||||
|
||||
NCollection_Utf8String is the only NCollection type the app names directly:
|
||||
it wraps the font path and the text to emboss. Constructed from a Python
|
||||
str, which nanobind hands over as UTF-8 already.
|
||||
*/
|
||||
|
||||
#include "../common/occt_module.h"
|
||||
|
||||
#include <NCollection_String.hxx>
|
||||
|
||||
void register_NCollection(nb::module_ &root) {
|
||||
nb::module_ m = ocp_submodule(root, "NCollection");
|
||||
|
||||
nb::class_<NCollection_Utf8String>(m, "NCollection_Utf8String")
|
||||
.def(nb::init<>())
|
||||
// Upstream also offers an explicit-length overload; the app always
|
||||
// passes a whole Python str, which arrives NUL-terminated, so only the
|
||||
// one-argument form is bound.
|
||||
.def(
|
||||
"__init__",
|
||||
[](NCollection_Utf8String *self, const char *text) {
|
||||
new (self) NCollection_Utf8String(text);
|
||||
},
|
||||
"theCopy"_a)
|
||||
.def("ToCString", &NCollection_Utf8String::ToCString)
|
||||
.def("Size", &NCollection_Utf8String::Size)
|
||||
.def("Length", &NCollection_Utf8String::Length)
|
||||
.def("IsEmpty", &NCollection_Utf8String::IsEmpty)
|
||||
.def("__str__", &NCollection_Utf8String::ToCString);
|
||||
}
|
||||
27
src/modules/mod_RWStl.cpp
Normal file
27
src/modules/mod_RWStl.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
OCP.RWStl — STL read.
|
||||
|
||||
Returns a bare Poly_Triangulation, which the app wraps into a shell of
|
||||
triangle faces itself. Nothing writes STL through OCCT: the app has its
|
||||
own writer, which welds and de-duplicates first.
|
||||
|
||||
Unlike the XSTEP readers this touches no global state, so it releases the
|
||||
GIL.
|
||||
*/
|
||||
|
||||
#include "../common/occt_module.h"
|
||||
#include "../common/occt_policies.h"
|
||||
|
||||
#include <Poly_Triangulation.hxx>
|
||||
#include <RWStl.hxx>
|
||||
|
||||
void register_RWStl(nb::module_ &root) {
|
||||
nb::module_ m = ocp_submodule(root, "RWStl");
|
||||
|
||||
nb::class_<RWStl> cls(m, "RWStl");
|
||||
|
||||
OCP_DEF_S(
|
||||
cls, "ReadFile",
|
||||
[](const Standard_CString file) { return RWStl::ReadFile(file); },
|
||||
"theFile"_a, OCP_NOGIL);
|
||||
}
|
||||
87
src/modules/mod_STEPControl.cpp
Normal file
87
src/modules/mod_STEPControl.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
OCP.STEPControl — STEP read and write.
|
||||
|
||||
The reader inherits its transfer surface from XSControl_Reader; what is
|
||||
added here is the unit handling the app needs (FileUnits reports what the
|
||||
file declares, SetSystemLengthUnit rescales the transfer) and ReadStream,
|
||||
which takes a Python file-like.
|
||||
|
||||
ReadStream reuses the slurp bridge from occt_stream.h rather than wrapping
|
||||
a streambuf that calls back into Python — same reasoning as BinTools, and
|
||||
the same one extra copy.
|
||||
|
||||
The GIL stays held throughout, per the note in mod_XSControl.cpp: XSTEP is
|
||||
built on process-global state and the app serialises imports anyway.
|
||||
|
||||
This is also where the S5 question lands (design.md): whether the wheel has
|
||||
to ship OCCT's share/ resources for STEP to resolve units in a container
|
||||
with no CSF_* environment. tests/test_inc3_io.py answers it.
|
||||
*/
|
||||
|
||||
#include "../common/occt_module.h"
|
||||
#include "../common/occt_policies.h"
|
||||
#include "../common/occt_stream.h"
|
||||
|
||||
#include <STEPControl_Controller.hxx>
|
||||
#include <STEPControl_Reader.hxx>
|
||||
#include <STEPControl_StepModelType.hxx>
|
||||
#include <STEPControl_Writer.hxx>
|
||||
#include <TColStd_SequenceOfAsciiString.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <XSControl_Reader.hxx>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
void register_STEPControl(nb::module_ &root) {
|
||||
nb::module_ m = ocp_submodule(root, "STEPControl");
|
||||
|
||||
nb::enum_<STEPControl_StepModelType>(m, "STEPControl_StepModelType",
|
||||
nb::is_arithmetic())
|
||||
.value("STEPControl_AsIs", STEPControl_AsIs)
|
||||
.value("STEPControl_ManifoldSolidBrep", STEPControl_ManifoldSolidBrep)
|
||||
.value("STEPControl_BrepWithVoids", STEPControl_BrepWithVoids)
|
||||
.value("STEPControl_FacetedBrep", STEPControl_FacetedBrep)
|
||||
.value("STEPControl_FacetedBrepAndBrepWithVoids",
|
||||
STEPControl_FacetedBrepAndBrepWithVoids)
|
||||
.value("STEPControl_ShellBasedSurfaceModel",
|
||||
STEPControl_ShellBasedSurfaceModel)
|
||||
.value("STEPControl_GeometricCurveSet", STEPControl_GeometricCurveSet)
|
||||
.value("STEPControl_Hybrid", STEPControl_Hybrid)
|
||||
.export_values();
|
||||
|
||||
nb::class_<STEPControl_Controller> controller(m, "STEPControl_Controller");
|
||||
OCP_DEF_S(
|
||||
controller, "Init", []() { return STEPControl_Controller::Init(); });
|
||||
|
||||
nb::class_<STEPControl_Reader, XSControl_Reader>(m, "STEPControl_Reader")
|
||||
.def(nb::init<>())
|
||||
.def(
|
||||
"ReadStream",
|
||||
[](STEPControl_Reader &self, const char *name, nb::handle stream) {
|
||||
std::istringstream buffer(ocp_slurp(stream));
|
||||
return self.ReadStream(name, buffer);
|
||||
},
|
||||
"theName"_a, "theIStream"_a)
|
||||
.def("FileUnits", &STEPControl_Reader::FileUnits, "theLengthUnits"_a,
|
||||
"theAngleUnits"_a, "theSolidAngleUnits"_a)
|
||||
.def("SetSystemLengthUnit", &STEPControl_Reader::SetSystemLengthUnit,
|
||||
"theLengthUnit"_a)
|
||||
.def("SystemLengthUnit", &STEPControl_Reader::SystemLengthUnit);
|
||||
|
||||
nb::class_<STEPControl_Writer>(m, "STEPControl_Writer")
|
||||
.def(nb::init<>())
|
||||
.def(
|
||||
"Transfer",
|
||||
[](STEPControl_Writer &self, const TopoDS_Shape &sh,
|
||||
const STEPControl_StepModelType mode,
|
||||
const Standard_Boolean compgraph) {
|
||||
return self.Transfer(sh, mode, compgraph);
|
||||
},
|
||||
"sh"_a, "mode"_a, "compgraph"_a = Standard_True)
|
||||
.def(
|
||||
"Write",
|
||||
[](STEPControl_Writer &self, const Standard_CString filename) {
|
||||
return self.Write(filename);
|
||||
},
|
||||
"filename"_a);
|
||||
}
|
||||
57
src/modules/mod_StdPrs.cpp
Normal file
57
src/modules/mod_StdPrs.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
OCP.StdPrs — glyph outlines as BRep.
|
||||
|
||||
Text emboss loads a bundled font and asks the builder for the text as a
|
||||
compound of face outlines, holes already subtracted, which it then extrudes
|
||||
into or out of the model.
|
||||
|
||||
These live in TKService, and both classes are real in 7.9.3 rather than the
|
||||
deprecated typedefs of Font_BRepFont/Font_BRepTextBuilder that OCCT 8.0
|
||||
turns them into — so the 8.0 port is a rename here and nothing else. The
|
||||
builder image already asserts TKService links without libGL or libX11, so
|
||||
binding them costs the runtime image nothing.
|
||||
|
||||
Rendering a glyph is FreeType work with no Python in it, so it releases the
|
||||
GIL.
|
||||
*/
|
||||
|
||||
#include "../common/occt_module.h"
|
||||
#include "../common/occt_policies.h"
|
||||
#include "../common/occt_transient.h"
|
||||
|
||||
#include <NCollection_String.hxx>
|
||||
#include <StdPrs_BRepFont.hxx>
|
||||
#include <StdPrs_BRepTextBuilder.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <gp_Ax3.hxx>
|
||||
|
||||
void register_StdPrs(nb::module_ &root) {
|
||||
nb::module_ m = ocp_submodule(root, "StdPrs");
|
||||
|
||||
nb::class_<StdPrs_BRepFont, Standard_Transient>(m, "StdPrs_BRepFont")
|
||||
.def(ocp_new<StdPrs_BRepFont>())
|
||||
.def(
|
||||
"Init",
|
||||
[](StdPrs_BRepFont &self, const NCollection_String &path,
|
||||
const Standard_Real size, const Standard_Integer faceId) {
|
||||
return self.Init(path, size, faceId);
|
||||
},
|
||||
"theFontPath"_a, "theSize"_a, "theFaceId"_a, OCP_NOGIL)
|
||||
.def("Release", &StdPrs_BRepFont::Release)
|
||||
.def("Ascender", &StdPrs_BRepFont::Ascender)
|
||||
.def("Descender", &StdPrs_BRepFont::Descender);
|
||||
|
||||
nb::class_<StdPrs_BRepTextBuilder>(m, "StdPrs_BRepTextBuilder")
|
||||
.def(nb::init<>())
|
||||
.def(
|
||||
"Perform",
|
||||
[](StdPrs_BRepTextBuilder &self, StdPrs_BRepFont &font,
|
||||
const NCollection_String &text, const gp_Ax3 &penLoc,
|
||||
const Graphic3d_HorizontalTextAlignment hAlign,
|
||||
const Graphic3d_VerticalTextAlignment vAlign) {
|
||||
return self.Perform(font, text, penLoc, hAlign, vAlign);
|
||||
},
|
||||
"theFont"_a, "theString"_a, "thePenLoc"_a = gp_Ax3(),
|
||||
"theHAlign"_a = Graphic3d_HTA_LEFT,
|
||||
"theVAlign"_a = Graphic3d_VTA_BOTTOM, OCP_RETURN_COPY, OCP_NOGIL);
|
||||
}
|
||||
33
src/modules/mod_XSControl.cpp
Normal file
33
src/modules/mod_XSControl.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
OCP.XSControl — the reader base STEP and IGES share.
|
||||
|
||||
Not imported by the app, but ReadFile/NbRootsForTransfer/TransferRoots/
|
||||
OneShape are declared here, so binding them once means neither concrete
|
||||
reader has to.
|
||||
|
||||
These keep the GIL, deliberately. The XSTEP layer traffics in
|
||||
process-global Interface_Static state, the IGES reader is documented as not
|
||||
thread-safe, and the app already serialises imports behind a lock — so
|
||||
holding the GIL costs nothing and removes a whole class of question. It is
|
||||
also what upstream does, which releases nowhere.
|
||||
*/
|
||||
|
||||
#include "../common/occt_module.h"
|
||||
#include "../common/occt_policies.h"
|
||||
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <XSControl_Reader.hxx>
|
||||
|
||||
void register_XSControl(nb::module_ &root) {
|
||||
nb::module_ m = ocp_submodule(root, "XSControl");
|
||||
|
||||
nb::class_<XSControl_Reader>(m, "XSControl_Reader")
|
||||
.def("ReadFile", &XSControl_Reader::ReadFile, "filename"_a)
|
||||
.def("NbRootsForTransfer", &XSControl_Reader::NbRootsForTransfer)
|
||||
.def(
|
||||
"TransferRoots",
|
||||
[](XSControl_Reader &self) { return self.TransferRoots(); })
|
||||
.def("NbShapes", &XSControl_Reader::NbShapes)
|
||||
.def("Shape", &XSControl_Reader::Shape, "num"_a = 1, OCP_RETURN_COPY)
|
||||
.def("OneShape", &XSControl_Reader::OneShape, OCP_RETURN_COPY);
|
||||
}
|
||||
@@ -92,6 +92,7 @@ void register_gp(nb::module_ &root) {
|
||||
.def("Crossed", &gp_Vec::Crossed, "Right"_a, OCP_RETURN_COPY)
|
||||
.def("Normalize", &gp_Vec::Normalize)
|
||||
.def("Normalized", &gp_Vec::Normalized, OCP_RETURN_COPY)
|
||||
.def("Reverse", &gp_Vec::Reverse)
|
||||
.def("Reversed", &gp_Vec::Reversed, OCP_RETURN_COPY)
|
||||
.def("Multiplied", &gp_Vec::Multiplied, "Scalar"_a, OCP_RETURN_COPY)
|
||||
.def("Angle", &gp_Vec::Angle, "Other"_a)
|
||||
@@ -146,6 +147,10 @@ void register_gp(nb::module_ &root) {
|
||||
.def("SetScale", &gp_Trsf::SetScale, "P"_a, "S"_a)
|
||||
.def("SetMirror", nb::overload_cast<const gp_Ax1 &>(&gp_Trsf::SetMirror),
|
||||
"A1"_a)
|
||||
.def("SetMirror", nb::overload_cast<const gp_Ax2 &>(&gp_Trsf::SetMirror),
|
||||
"A2"_a)
|
||||
.def("SetMirror", nb::overload_cast<const gp_Pnt &>(&gp_Trsf::SetMirror),
|
||||
"P"_a)
|
||||
.def("Form", &gp_Trsf::Form)
|
||||
.def("ScaleFactor", &gp_Trsf::ScaleFactor)
|
||||
.def("TranslationPart", &gp_Trsf::TranslationPart, OCP_RETURN_COPY)
|
||||
|
||||
Reference in New Issue
Block a user