#ifdef NG_PYTHON #include <../general/ngpython.hpp> #include #include #include "../meshing/python_mesh.hpp" using namespace netgen; namespace netgen { extern shared_ptr ng_geometry; } // a shadow solid tree using shared pointers. class SPSolid { shared_ptr s1, s2; Solid * solid; int bc = -1; string bcname = ""; double maxh = -1; string material; bool owner; double red = 0, green = 0, blue = 1; bool transp = false; public: enum optyp { TERM, SECTION, UNION, SUB, EXISTING }; SPSolid (Solid * as) : solid(as), owner(true), op(TERM) { ; } SPSolid (Solid * as, int /*dummy*/) : solid(as), owner(false), op(EXISTING) { ; } ~SPSolid () { ; // if (owner) delete solid; } SPSolid (optyp aop, shared_ptr as1, shared_ptr as2) : s1(as1), s2(as2), owner(true), op(aop) { if (aop == UNION) solid = new Solid (Solid::UNION, s1->GetSolid(), s2->GetSolid()); else if (aop == SECTION) solid = new Solid (Solid::SECTION, s1->GetSolid(), s2->GetSolid()); else if (aop == SUB) solid = new Solid (Solid::SUB, s1->GetSolid()); // , s2->GetSolid()); } Solid * GetSolid() { return solid; } const Solid * GetSolid() const { return solid; } void GiveUpOwner() { owner = false; if (s1) s1 -> GiveUpOwner(); if (s2) s2 -> GiveUpOwner(); } void AddSurfaces(CSGeometry & geom) { if (op == TERM) geom.AddSurfaces (solid->GetPrimitive()); if (s1) s1 -> AddSurfaces (geom); if (s2) s2 -> AddSurfaces (geom); } void SetMaterial (string mat) { material = mat; } string GetMaterial () { if (!material.empty()) return material; if (s1) { string s1mat = s1->GetMaterial(); if (!s1mat.empty()) return s1mat; } if (s2) { string s2mat = s2->GetMaterial(); if (!s2mat.empty()) return s2mat; } return material; } void SetBC(int abc) { if (bc == -1) { bc = abc; if (s1) s1 -> SetBC(bc); if (s2) s2 -> SetBC(bc); if (op == TERM) { Primitive * prim = solid -> GetPrimitive(); for (int i = 0; i < prim->GetNSurfaces(); i++) prim->GetSurface(i).SetBCProperty (abc); // cout << "set " << prim->GetNSurfaces() << " surfaces to bc " << bc << endl; } } } void SetBCName(string name) { if (bcname == "") { bcname = name; if (s1) s1 -> SetBCName(name); if (s2) s2 -> SetBCName(name); if (op == TERM) { Primitive * prim = solid -> GetPrimitive(); for (int i = 0; i < prim->GetNSurfaces(); i++) prim->GetSurface(i).SetBCName (name); // cout << "set " << prim->GetNSurfaces() << " surfaces to bc " << bc << endl; } } } void SetMaxH(double amaxh) { if (maxh == -1) { maxh = amaxh; if (s1) s1 -> SetMaxH(maxh); if (s2) s2 -> SetMaxH(maxh); if (op == TERM) { Primitive * prim = solid -> GetPrimitive(); for (int i = 0; i < prim->GetNSurfaces(); i++) prim->GetSurface(i).SetMaxH (maxh); } } } void SetColor(double ared, double agreen, double ablue) { red = ared; green = agreen; blue = ablue; } double GetRed() const { return red; } double GetGreen() const { return green; } double GetBlue() const { return blue; } void SetTransparent() { transp = true; } bool IsTransparent() { return transp; } private: optyp op; }; inline ostream & operator<< (ostream & ost, const SPSolid & sol) { ost << *sol.GetSolid(); return ost; } namespace netgen { extern CSGeometry * ParseCSG (istream & istr, CSGeometry *instance=nullptr); } DLL_HEADER void ExportCSG(py::module &m) { py::class_> (m, "SplineCurve2d") .def(py::init<>()) .def ("AddPoint", FunctionPointer ([] (SplineGeometry<2> & self, double x, double y) { self.geompoints.Append (GeomPoint<2> (Point<2> (x,y))); return self.geompoints.Size()-1; })) .def ("AddSegment", FunctionPointer ([] (SplineGeometry<2> & self, int i1, int i2) { self.splines.Append (new LineSeg<2> (self.geompoints[i1], self.geompoints[i2])); })) .def ("AddSegment", FunctionPointer ([] (SplineGeometry<2> & self, int i1, int i2, int i3) { self.splines.Append (new SplineSeg3<2> (self.geompoints[i1], self.geompoints[i2], self.geompoints[i3])); })) ; py::class_,shared_ptr>> (m,"SplineCurve3d") .def(py::init<>()) .def ("AddPoint", FunctionPointer ([] (SplineGeometry<3> & self, double x, double y, double z) { self.geompoints.Append (GeomPoint<3> (Point<3> (x,y,z))); return self.geompoints.Size()-1; })) .def ("AddSegment", FunctionPointer ([] (SplineGeometry<3> & self, int i1, int i2) { self.splines.Append (new LineSeg<3> (self.geompoints[i1], self.geompoints[i2])); })) .def ("AddSegment", FunctionPointer ([] (SplineGeometry<3> & self, int i1, int i2, int i3) { self.splines.Append (new SplineSeg3<3> (self.geompoints[i1], self.geompoints[i2], self.geompoints[i3])); })) ; py::class_> (m, "SplineSurface", "A surface for co dim 2 integrals on the splines") .def(py::init([](shared_ptr base, py::list cuts) { auto primitive = dynamic_cast (base->GetSolid()->GetPrimitive()); auto acuts = make_shared>>(); for(int i = 0; i> sps(cuts[i]); if(!sps.check()) throw NgException("Cut must be SurfacePrimitive in constructor of SplineSurface!"); auto sp = dynamic_cast(sps()->GetSolid()->GetPrimitive()); if(sp) acuts->Append(shared_ptr(sp)); else throw Exception("Cut must be SurfacePrimitive in constructor of SplineSurface!"); } if(!primitive) throw Exception("Base is not a SurfacePrimitive in constructor of SplineSurface!"); return make_shared(shared_ptr(primitive),acuts); }),py::arg("base"), py::arg("cuts")=py::list()) .def("AddPoint", FunctionPointer ([] (SplineSurface & self, double x, double y, double z, bool hpref) { self.AppendPoint(Point<3>(x,y,z),hpref); return self.GetNP()-1; }), py::arg("x"),py::arg("y"),py::arg("z"),py::arg("hpref")=false) .def("AddSegment", [] (SplineSurface & self, int i1, int i2, string bcname, double maxh) { auto seg = make_shared>(self.GetPoint(i1),self.GetPoint(i2)); self.AppendSegment(seg,bcname,maxh); }, py::arg("pnt1"),py::arg("pnt2"),py::arg("bcname")="default", py::arg("maxh")=-1.) .def("AddSegment", [] (SplineSurface& self, int i1, int i2, int i3, string bcname, double maxh) { auto seg = make_shared>(self.GetPoint(i1), self.GetPoint(i2), self.GetPoint(i3)); self.AppendSegment(seg, bcname, maxh); }, py::arg("pnt1"),py::arg("pnt2"), py::arg("pnt3"),py::arg("bcname")="default", py::arg("maxh")=-1.) ; py::class_> (m, "Solid") .def ("__str__", &ToString) .def ("__add__", FunctionPointer( [] ( shared_ptr self, shared_ptr other) { return make_shared (SPSolid::UNION, self, other); })) .def ("__mul__", FunctionPointer( [] ( shared_ptr self, shared_ptr other) { return make_shared (SPSolid::SECTION, self, other); })) .def ("__sub__", FunctionPointer ([] ( shared_ptr self, shared_ptr other) { return make_shared (SPSolid::SECTION, self, make_shared (SPSolid::SUB, other, nullptr)); })) .def ("bc", FunctionPointer([](shared_ptr & self, int nr) -> shared_ptr { self->SetBC(nr); return self; })) .def ("bc", FunctionPointer([](shared_ptr & self, string name) -> shared_ptr { self->SetBCName(name); return self; })) .def ("maxh", FunctionPointer([](shared_ptr & self, double maxh) -> shared_ptr { self->SetMaxH(maxh); return self; })) .def ("mat", FunctionPointer([](shared_ptr & self, string mat) -> shared_ptr { self->SetMaterial(mat); return self; })) .def ("mat", &SPSolid::GetMaterial) .def("col", FunctionPointer([](shared_ptr & self, py::list rgb) -> shared_ptr { py::extract red(rgb[0]); py::extract green(rgb[1]); py::extract blue(rgb[2]); self->SetColor(red(),green(),blue()); return self; })) .def("transp", FunctionPointer([](shared_ptr & self)->shared_ptr < SPSolid > { self->SetTransparent(); return self; })) ; m.def ("Sphere", FunctionPointer([](Point<3> c, double r) { Sphere * sp = new Sphere (c, r); Solid * sol = new Solid (sp); return make_shared (sol); })); m.def ("Ellipsoid", FunctionPointer([](Point<3> m, Vec<3> a, Vec<3> b, Vec<3> c) { Ellipsoid * ell = new Ellipsoid (m, a, b, c); Solid * sol = new Solid (ell); return make_shared (sol); })); m.def ("Plane", FunctionPointer([](Point<3> p, Vec<3> n) { Plane * sp = new Plane (p,n); Solid * sol = new Solid (sp); return make_shared (sol); })); m.def ("Cone", FunctionPointer([](Point<3> a, Point<3> b, double ra, double rb) { Cone * cyl = new Cone (a, b, ra, rb); Solid * sol = new Solid (cyl); return make_shared (sol); })); m.def ("Cylinder", FunctionPointer([](Point<3> a, Point<3> b, double r) { Cylinder * cyl = new Cylinder (a, b, r); Solid * sol = new Solid (cyl); return make_shared (sol); })); m.def ("OrthoBrick", FunctionPointer([](Point<3> p1, Point<3> p2) { OrthoBrick * brick = new OrthoBrick (p1,p2); Solid * sol = new Solid (brick); return make_shared (sol); })); m.def ("Torus", FunctionPointer([](Point<3> c, Vec<3> n, double R, double r) { Torus * torus = new Torus (c,n,R,r); Solid * sol = new Solid (torus); return make_shared (sol); })); m.def ("Revolution", FunctionPointer([](Point<3> p1, Point<3> p2, const SplineGeometry<2> & spline) { Revolution * rev = new Revolution (p1, p2, spline); Solid * sol = new Solid(rev); return make_shared (sol); })); m.def ("Extrusion", FunctionPointer([](const SplineGeometry<3> & path, const SplineGeometry<2> & profile, Vec<3> n) { Extrusion * extr = new Extrusion (path,profile,n); Solid * sol = new Solid(extr); return make_shared (sol); })); m.def("EllipticCone", [](const Point<3>& a, const Vec<3>& v, const Vec<3>& w, double h, double r) { auto ellcone = new EllipticCone(a,v,w,h,r); auto sol = new Solid(ellcone); return make_shared(sol); }, py::arg("a"), py::arg("vl"), py::arg("vs"), py::arg("h"), py::arg("r"), R"raw_string( An elliptic cone, given by the point 'a' at the base of the cone along the main axis, the vectors v and w of the long and short axis of the ellipse, respectively, the height of the cone, h, and ratio of base long axis length to top long axis length, r Note: The elliptic cone has to be truncated by planes similar to a cone or an elliptic cylinder. When r =1, the truncated elliptic cone becomes an elliptic cylinder. When r tends to zero, the truncated elliptic cone tends to a full elliptic cone. However, when r = 0, the top part becomes a point(tip) and meshing fails! )raw_string"); m.def ("Or", FunctionPointer([](shared_ptr s1, shared_ptr s2) { return make_shared (SPSolid::UNION, s1, s2); })); m.def ("And", FunctionPointer([](shared_ptr s1, shared_ptr s2) { return make_shared (SPSolid::SECTION, s1, s2); })); py::class_> (m, "CSGeometry") .def(py::init<>()) .def(py::init([](const string& filename) { ifstream ist (filename); auto geo = make_shared(); ParseCSG(ist, geo.get()); geo->FindIdenticSurfaces(1e-8 * geo->MaxSize()); return geo; }), py::arg("filename")) .def(NGSPickle()) .def("Save", FunctionPointer([] (CSGeometry & self, string filename) { cout << "save geometry to file " << filename << endl; self.Save (filename); })) .def("Add", [] (CSGeometry & self, shared_ptr solid, py::list bcmod, double maxh, py::tuple col, bool transparent, int layer) { solid->AddSurfaces (self); solid->GiveUpOwner(); int tlonr = self.SetTopLevelObject (solid->GetSolid()); self.GetTopLevelObject(tlonr) -> SetMaterial(solid->GetMaterial()); self.GetTopLevelObject(tlonr) -> SetRGB(solid->GetRed(),solid->GetGreen(),solid->GetBlue()); // self.GetTopLevelObject(tlonr)->SetTransparent(solid->IsTransparent()); self.GetTopLevelObject(tlonr)->SetTransparent(transparent); self.GetTopLevelObject(tlonr)->SetMaxH(maxh); self.GetTopLevelObject(tlonr)->SetLayer(layer); // cout << "rgb = " << py::len(rgb) << endl; if (py::len(col)==3) self.GetTopLevelObject(tlonr) -> SetRGB(py::cast(col[0]), py::cast(col[1]), py::cast(col[2])); // bcmod is list of tuples ( solid, bcnr ) for (int i = 0; i < py::len(bcmod); i++) { py::tuple tup = py::extract (bcmod[i]) (); auto mod_solid = py::extract> (tup[0]) (); int mod_nr = -1; string * bcname = nullptr; py::object val = tup[1]; if (py::extract(val).check()) mod_nr = py::extract (val)(); if (py::extract(val).check()) bcname = new string ( py::extract (val)()); NgArray si; mod_solid -> GetSolid() -> GetSurfaceIndices (si); // cout << "change bc on surfaces: " << si << " to " << mod_nr << endl; for (int j = 0; j < si.Size(); j++) { CSGeometry::BCModification bcm; bcm.bcname = bcname ? new string (*bcname) : nullptr; bcm.tlonr = tlonr; bcm.si = si[j]; bcm.bcnr = mod_nr; self.bcmodifications.Append (bcm); } delete bcname; } return tlonr; }, py::arg("solid"), py::arg("bcmod")=py::list(), py::arg("maxh")=1e99, py::arg("col")=py::tuple(), py::arg("transparent")=false, py::arg("layer")=1 ) .def("AddSurface", FunctionPointer ([] (CSGeometry & self, shared_ptr surface, shared_ptr solid) { solid->AddSurfaces (self); solid->GiveUpOwner(); Surface & surf = surface->GetSolid()->GetPrimitive()->GetSurface(); int tlonr = self.SetTopLevelObject (solid->GetSolid(), &surf); // self.GetTopLevelObject(tlonr) -> SetMaterial(solid->GetMaterial()); self.GetTopLevelObject(tlonr) -> SetBCProp(surf.GetBCProperty()); self.GetTopLevelObject(tlonr) -> SetBCName(surf.GetBCName()); self.GetTopLevelObject(tlonr) -> SetRGB(solid->GetRed(),solid->GetGreen(),solid->GetBlue()); self.GetTopLevelObject(tlonr)->SetTransparent(solid->IsTransparent()); }), py::arg("surface"), py::arg("solid") ) .def("AddSplineSurface", FunctionPointer ([] (CSGeometry & self, shared_ptr surf) { auto cuttings = surf->CreateCuttingSurfaces(); auto spsol = make_shared(new Solid(surf.get())); for(auto cut : (*cuttings)){ spsol = make_shared(SPSolid::SECTION,spsol,make_shared(new Solid(cut.get()))); } spsol->AddSurfaces(self); int tlonr = self.SetTopLevelObject(spsol->GetSolid(), surf.get()); self.GetTopLevelObject(tlonr) -> SetBCProp(surf->GetBase()->GetBCProperty()); self.GetTopLevelObject(tlonr) -> SetBCName(surf->GetBase()->GetBCName()); self.GetTopLevelObject(tlonr) -> SetMaxH(surf->GetBase()->GetMaxH()); NgArray> non_midpoints; for(auto spline : surf->GetSplines()) { non_midpoints.Append(spline->GetPoint(0)); } for(auto p : non_midpoints) self.AddUserPoint(p); self.AddSplineSurface(surf); }), py::arg("SplineSurface")) .def("SingularFace", [] (CSGeometry & self, shared_ptr sol, shared_ptr surfaces, double factor) { int tlonum = -1; for (int i = 0; i < self.GetNTopLevelObjects(); i++) if (self.GetTopLevelObject(i)->GetSolid() == sol->GetSolid()) tlonum = i; if (tlonum == -1) throw NgException("not a top-level-object"); if (!surfaces) surfaces = sol; auto singface = new SingularFace(tlonum+1, surfaces->GetSolid(), factor); self.singfaces.Append(singface); }, py::arg("solid"), py::arg("surfaces")=nullptr, py::arg("factor")=0.25) .def("SingularEdge", [] (CSGeometry & self, shared_ptr s1,shared_ptr s2, double factor) { auto singedge = new SingularEdge(1, -1, self, s1->GetSolid(), s2->GetSolid(), factor); self.singedges.Append (singedge); }) .def("SingularPoint", [] (CSGeometry & self, shared_ptr s1,shared_ptr s2, shared_ptr s3, double factor) { auto singpoint = new SingularPoint(1, s1->GetSolid(), s2->GetSolid(), s3->GetSolid(), factor); self.singpoints.Append (singpoint); }) .def("CloseSurfaces", FunctionPointer ([] (CSGeometry & self, shared_ptr s1, shared_ptr s2, py::list aslices ) { NgArray si1, si2; s1->GetSolid()->GetSurfaceIndices (si1); s2->GetSolid()->GetSurfaceIndices (si2); cout << "surface ids1 = " << si1 << endl; cout << "surface ids2 = " << si2 << endl; Flags flags; try { int n = py::len(aslices); Array slices(n); for(int i=0; i(aslices[i])(); } flags.SetFlag("slices", slices); } catch( py::error_already_set const & ) { cout << "caught python error:" << endl; PyErr_Print(); } const TopLevelObject * domain = nullptr; self.AddIdentification (new CloseSurfaceIdentification (self.GetNIdentifications()+1, self, self.GetSurface (si1[0]), self.GetSurface (si2[0]), domain, flags)); }), py::arg("solid1"), py::arg("solid2"), py::arg("slices") ) .def("CloseSurfaces", FunctionPointer ([] (CSGeometry & self, shared_ptr s1, shared_ptr s2, int reflevels, shared_ptr domain_solid) { NgArray si1, si2; s1->GetSolid()->GetSurfaceIndices (si1); s2->GetSolid()->GetSurfaceIndices (si2); cout << "surface ids1 = " << si1 << endl; cout << "surface ids2 = " << si2 << endl; Flags flags; const TopLevelObject * domain = nullptr; if (domain_solid) domain = self.GetTopLevelObject(domain_solid->GetSolid()); self.AddIdentification (new CloseSurfaceIdentification (self.GetNIdentifications()+1, self, self.GetSurface (si1[0]), self.GetSurface (si2[0]), domain, flags)); }), py::arg("solid1"), py::arg("solid2"), py::arg("reflevels")=2, py::arg("domain")=nullptr ) .def("PeriodicSurfaces", FunctionPointer ([] (CSGeometry & self, shared_ptr s1, shared_ptr s2, Transformation<3> trafo) { NgArray si1, si2; s1->GetSolid()->GetSurfaceIndices (si1); s2->GetSolid()->GetSurfaceIndices (si2); cout << "identify surfaces " << si1[0] << " and " << si2[0] << endl; self.AddIdentification (new PeriodicIdentification (self.GetNIdentifications()+1, self, self.GetSurface (si1[0]), self.GetSurface (si2[0]), trafo)); }), py::arg("solid1"), py::arg("solid2"), py::arg("trafo")=Transformation<3>(Vec<3>(0,0,0)) ) .def("AddPoint", [] (CSGeometry & self, Point<3> p, int index) -> CSGeometry& { self.AddUserPoint(CSGeometry::UserPoint(p, index)); return self; }) .def("GetTransparent", FunctionPointer ([] (CSGeometry & self, int tlonr) { return self.GetTopLevelObject(tlonr)->GetTransparent(); }), py::arg("tlonr") ) .def("SetTransparent", FunctionPointer ([] (CSGeometry & self, int tlonr, bool transparent) { self.GetTopLevelObject(tlonr)->SetTransparent(transparent); }), py::arg("tlonr"), py::arg("transparent") ) .def("GetVisible", FunctionPointer ([] (CSGeometry & self, int tlonr) { return self.GetTopLevelObject(tlonr)->GetVisible(); }), py::arg("tlonr") ) .def("SetVisible", FunctionPointer ([] (CSGeometry & self, int tlonr, bool visible) { self.GetTopLevelObject(tlonr)->SetVisible(visible); }), py::arg("tlonr"), py::arg("visible") ) .def("SetBoundingBox", FunctionPointer ([] (CSGeometry & self, Point<3> pmin, Point<3> pmax) { self.SetBoundingBox(Box<3> (pmin, pmax)); }), py::arg("pmin"), py::arg("pmax") ) .def("Draw", FunctionPointer ([] (shared_ptr self) { self->FindIdenticSurfaces(1e-6); self->CalcTriangleApproximation(0.01, 20); ng_geometry = self; }) ) .def("GetSolids", [](CSGeometry& self) { py::list lst; for(auto i : Range(self.GetSolids().Size())) lst.append(make_shared(self.GetSolids()[i], 1234)); return lst; }) .def_property_readonly ("ntlo", &CSGeometry::GetNTopLevelObjects) .def("_visualizationData", [](shared_ptr csg_geo) { std::vector vertices; std::vector trigs; std::vector normals; std::vector min = {std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max()}; std::vector max = {std::numeric_limits::lowest(), std::numeric_limits::lowest(), std::numeric_limits::lowest()}; std::vector surfnames; for (int i = 0; i < csg_geo->GetNSurf(); i++) { auto surf = csg_geo->GetSurface(i); surfnames.push_back(surf->GetBCName()); } csg_geo->FindIdenticSurfaces(1e-6); csg_geo->CalcTriangleApproximation(0.01,100); auto nto = csg_geo->GetNTopLevelObjects(); size_t np = 0; size_t ntrig = 0; for (int i = 0; i < nto; i++){ np += csg_geo->GetTriApprox(i)->GetNP(); ntrig += csg_geo->GetTriApprox(i)->GetNT(); } vertices.reserve(np*3); trigs.reserve(ntrig*4); normals.reserve(np*3); int offset_points = 0; for (int i = 0; i < nto; i++) { auto triapprox = csg_geo->GetTriApprox(i); for (int j = 0; j < triapprox->GetNP(); j++) for(int k = 0; k < 3; k++) { float val = triapprox->GetPoint(j)[k]; vertices.push_back(val); min[k] = min2(min[k], val); max[k] = max2(max[k],val); normals.push_back(triapprox->GetNormal(j)[k]); } for (int j = 0; j < triapprox->GetNT(); j++) { for(int k = 0; k < 3; k++) trigs.push_back(triapprox->GetTriangle(j)[k]+offset_points); trigs.push_back(triapprox->GetTriangle(j).SurfaceIndex()); } offset_points += triapprox->GetNP(); } py::gil_scoped_acquire ac; py::dict res; py::list snames; for(auto name : surfnames) snames.append(py::cast(name)); res["vertices"] = MoveToNumpy(vertices); res["triangles"] = MoveToNumpy(trigs); res["normals"] = MoveToNumpy(normals); res["surfnames"] = snames; res["min"] = MoveToNumpy(min); res["max"] = MoveToNumpy(max); return res; }, py::call_guard()) .def("GenerateMesh", [](shared_ptr geo, MeshingParameters* pars, py::kwargs kwargs) { MeshingParameters mp; if(pars) mp = *pars; { py::gil_scoped_acquire aq; CreateMPfromKwargs(mp, kwargs); } auto mesh = make_shared(); SetGlobalMesh (mesh); mesh->SetGeometry(geo); ng_geometry = geo; geo->FindIdenticSurfaces(1e-8 * geo->MaxSize()); auto result = geo->GenerateMesh (mesh, mp); if(result != 0) throw Exception("Meshing failed!"); return mesh; }, py::arg("mp") = nullptr, meshingparameter_description.c_str(), py::call_guard()) ; m.def("Save", FunctionPointer ([](const Mesh & self, const string & filename, const CSGeometry & geom) { ostream * outfile; if (filename.substr (filename.length()-3, 3) == ".gz") outfile = new ogzstream (filename.c_str()); else outfile = new ofstream (filename.c_str()); self.Save (*outfile); *outfile << endl << endl << "endmesh" << endl << endl; geom.SaveToMeshFile (*outfile); delete outfile; }),py::call_guard()) ; m.def("ZRefinement", FunctionPointer ([](Mesh & mesh, CSGeometry & geom) { ZRefinementOptions opt; opt.minref = 5; ZRefinement (mesh, &geom, opt); }),py::call_guard()) ; } PYBIND11_MODULE(libcsg, m) { ExportCSG(m); } #endif