pickling for all geometry types

This commit is contained in:
Christopher Lackner 2018-12-14 12:01:58 +01:00
parent cdd871282e
commit 099acc9fa1
21 changed files with 281 additions and 140 deletions

View File

@ -1592,5 +1592,5 @@ namespace netgen
};
CSGInit csginit;
static RegisterClassForArchive<CSGeometry, NetgenGeometry> regcsg;
}

View File

@ -177,14 +177,14 @@ namespace netgen
void Clean ();
virtual void Save (string filename) const;
virtual void Save (string filename) const override;
void Save (ostream & ost) const;
void Load (istream & ist);
void SaveSurfaces (ostream & out) const;
void LoadSurfaces (istream & in);
virtual void SaveToMeshFile (ostream & ost) const;
virtual void SaveToMeshFile (ostream & ost) const override;
int GetChangeVal() { return changeval; }
void Change() { changeval++; }
@ -211,7 +211,7 @@ namespace netgen
const SplineGeometry<2> * GetSplineCurve2d (const string & name) const;
const SplineGeometry<3> * GetSplineCurve3d (const string & name) const;
void DoArchive(Archive& archive);
void DoArchive(Archive& archive) override;
void SetFlags (const char * solidname, const Flags & flags);
@ -344,9 +344,9 @@ namespace netgen
Array<BCModification> bcmodifications;
virtual int GenerateMesh (shared_ptr<Mesh> & mesh, MeshingParameters & mparam);
virtual int GenerateMesh (shared_ptr<Mesh> & mesh, MeshingParameters & mparam) override;
virtual const Refinement & GetRefinement () const;
virtual const Refinement & GetRefinement () const override;
void AddSplineSurface (shared_ptr<SplineSurface> ss) { spline_surfaces.Append(ss); }
};

View File

@ -1034,5 +1034,6 @@ namespace netgen
};
SplineGeoInit sginit;
static RegisterClassForArchive<SplineGeometry2d, SplineGeometry<2>, NetgenGeometry> regspg2;
static RegisterClassForArchive<SplineSegExt, SplineSeg<2>> regssext;
}

View File

@ -151,7 +151,11 @@ namespace netgen
void TestComment ( ifstream & infile ) ;
void DoArchive(Archive& ar)
{
SplineGeometry<2>::DoArchive(ar);
ar & materials & maxh & quadmeshing & tensormeshing & layer & bcnames & elto0;
}
const SplineSegExt & GetSpline (const int i) const
{

View File

@ -19,15 +19,30 @@ DLL_HEADER void ExportGeom2d(py::module &m)
(m, "SplineGeometry",
"a 2d boundary representation geometry model by lines and splines")
.def(py::init<>())
.def("__init__",
[](SplineGeometry2d *instance, const string & filename)
{
cout << "load geometry";
ifstream ist(filename);
new (instance) SplineGeometry2d();
instance->Load (filename.c_str());
ng_geometry = shared_ptr<SplineGeometry2d>(instance, NOOP_Deleter);
})
.def(py::init([](const string& filename)
{
auto geo = make_shared<SplineGeometry2d>();
geo->Load(filename.c_str());
ng_geometry = geo;
return geo;
}))
.def(py::pickle(
[](SplineGeometry2d& self)
{
auto ss = make_shared<stringstream>();
BinaryOutArchive archive(ss);
archive & self;
archive.FlushBuffer();
return py::make_tuple(py::bytes(ss->str()));
},
[](py::tuple state)
{
auto geo = make_shared<SplineGeometry2d>();
auto ss = make_shared<stringstream> (py::cast<py::bytes>(state[0]));
BinaryInArchive archive(ss);
archive & (*geo);
return geo;
}))
.def("Load",&SplineGeometry2d::Load)
.def("AppendPoint", FunctionPointer

View File

@ -129,6 +129,8 @@ namespace netgen
template class SplineGeometry<2>;
template class SplineGeometry<3>;
static RegisterClassForArchive<SplineGeometry<2>> regsp2;
static RegisterClassForArchive<SplineGeometry<3>> regsp3;
}

View File

@ -34,6 +34,11 @@ namespace netgen
DLL_HEADER int Load (const Array<double> & raw_data, const int startpos = 0);
virtual void DoArchive(Archive& ar)
{
ar & geompoints & splines;
}
DLL_HEADER void GetRawData (Array<double> & raw_data) const;
@ -55,11 +60,6 @@ namespace netgen
// void SetGrading (const double grading);
DLL_HEADER void AppendPoint (const Point<D> & p, const double reffac = 1., const bool hpref = false);
void DoArchive(Archive& ar)
{
ar & geompoints & splines;
}
void AppendSegment(SplineSeg<D> * spline)
{
splines.Append (spline);

View File

@ -74,4 +74,5 @@ namespace netgen
throw NgException("Cannot save geometry - no geometry available");
}
static RegisterClassForArchive<NetgenGeometry> regnggeo;
}

View File

@ -22,6 +22,9 @@ namespace netgen
virtual const Refinement & GetRefinement () const;
virtual void DoArchive(Archive&)
{ throw NgException("DoArchive not implemented for " + Demangle(typeid(*this).name())); }
virtual void Save (string filename) const;
virtual void SaveToMeshFile (ostream & /* ost */) const { ; }
};

View File

@ -48,6 +48,11 @@ public:
int GetOrder () { return order; }
virtual void DoArchive(Archive& ar)
{
ar & edgeorder & faceorder & edgecoeffsindex & facecoeffsindex & edgecoeffs & facecoeffs
& edgeweight & order & rational & ishighorder;
}
bool IsSegmentCurved (SegmentIndex segnr) const;
bool IsSurfaceElementCurved (SurfaceElementIndex sei) const;

View File

@ -1316,27 +1316,8 @@ namespace netgen
archive & *ident;
// archive geometry
if (archive.Output())
{
ostringstream ost;
if (geometry)
geometry -> SaveToMeshFile (ost);
archive << ost.str();
archive << (geometry ? curvedelems->GetOrder() : 1);
}
else
{
string str;
archive & str;
istringstream ist(str);
geometry = geometryregister.LoadFromMeshFile (ist);
int order;
archive & order;
if(geometry && order > 1)
BuildCurvedElements(order);
}
archive & geometry;
archive & *curvedelems;
if (archive.Input())
{

View File

@ -488,7 +488,7 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m)
auto mesh = make_shared<Mesh>();
mesh -> SetDimension(dim);
SetGlobalMesh(mesh); // for visualization
mesh -> SetGeometry (make_shared<NetgenGeometry>());
mesh -> SetGeometry (nullptr);
return mesh;
} ),
py::arg("dim")=3
@ -565,8 +565,6 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m)
break;
}
}
if (!ng_geometry)
ng_geometry = make_shared<NetgenGeometry>();
self.SetGeometry(ng_geometry);
delete infile;
}),py::call_guard<py::gil_scoped_release>())

View File

@ -3,6 +3,7 @@
#include <mystdlib.h>
#include <occgeom.hpp>
#include <cstdio>
#include "ShapeAnalysis_ShapeTolerance.hxx"
#include "ShapeAnalysis_ShapeContents.hxx"
#include "ShapeAnalysis_CheckSmallFace.hxx"
@ -1106,94 +1107,8 @@ void STEP_GetEntityName(const TopoDS_Shape & theShape, STEPCAFControl_Reader * a
// }
// Philippose - 23/02/2009
/* Special IGES File load function including the ability
to extract individual surface colours via the extended
OpenCascade XDE and XCAF Feature set.
*/
OCCGeometry *LoadOCC_IGES(const char *filename)
{
OCCGeometry *occgeo;
occgeo = new OCCGeometry;
// Initiate a dummy XCAF Application to handle the IGES XCAF Document
static Handle_XCAFApp_Application dummy_app = XCAFApp_Application::GetApplication();
// Create an XCAF Document to contain the IGES file itself
Handle_TDocStd_Document iges_doc;
// Check if a IGES File is already open under this handle, if so, close it to prevent
// Segmentation Faults when trying to create a new document
if(dummy_app->NbDocuments() > 0)
{
dummy_app->GetDocument(1,iges_doc);
dummy_app->Close(iges_doc);
}
dummy_app->NewDocument ("IGES-XCAF",iges_doc);
IGESCAFControl_Reader reader;
Standard_Integer stat = reader.ReadFile((char*)filename);
if(stat != IFSelect_RetDone)
{
delete occgeo;
return NULL;
}
// Enable transfer of colours
reader.SetColorMode(Standard_True);
reader.Transfer(iges_doc);
// Read in the shape(s) and the colours present in the IGES File
Handle_XCAFDoc_ShapeTool iges_shape_contents = XCAFDoc_DocumentTool::ShapeTool(iges_doc->Main());
Handle_XCAFDoc_ColorTool iges_colour_contents = XCAFDoc_DocumentTool::ColorTool(iges_doc->Main());
TDF_LabelSequence iges_shapes;
iges_shape_contents->GetShapes(iges_shapes);
// List out the available colours in the IGES File as Colour Names
TDF_LabelSequence all_colours;
iges_colour_contents->GetColors(all_colours);
PrintMessage(1,"Number of colours in IGES File: ",all_colours.Length());
for(int i = 1; i <= all_colours.Length(); i++)
{
Quantity_Color col;
stringstream col_rgb;
iges_colour_contents->GetColor(all_colours.Value(i),col);
col_rgb << " : (" << col.Red() << "," << col.Green() << "," << col.Blue() << ")";
PrintMessage(1, "Colour [", i, "] = ",col.StringName(col.Name()),col_rgb.str());
}
// For the IGES Reader, all the shapes can be exported as one compound shape
// using the "OneShape" member
occgeo->shape = reader.OneShape();
occgeo->face_colours = iges_colour_contents;
occgeo->changed = 1;
occgeo->BuildFMap();
occgeo->CalcBoundingBox();
PrintContents (occgeo);
return occgeo;
}
// Philippose - 29/01/2009
/* Special STEP File load function including the ability
to extract individual surface colours via the extended
OpenCascade XDE and XCAF Feature set.
*/
OCCGeometry * LoadOCC_STEP (const char * filename)
{
OCCGeometry * occgeo;
occgeo = new OCCGeometry;
void LoadOCCInto(OCCGeometry* occgeo, const char* filename)
{
// Initiate a dummy XCAF Application to handle the STEP XCAF Document
static Handle_XCAFApp_Application dummy_app = XCAFApp_Application::GetApplication();
@ -1219,8 +1134,7 @@ void STEP_GetEntityName(const TopoDS_Shape & theShape, STEPCAFControl_Reader * a
if(stat != IFSelect_RetDone)
{
delete occgeo;
return NULL;
throw NgException("Couldn't load OCC geometry");
}
reader.Transfer(step_doc);
@ -1287,6 +1201,94 @@ void STEP_GetEntityName(const TopoDS_Shape & theShape, STEPCAFControl_Reader * a
// cout << occgeo->enames[i] << endl;
// cout << " " <<endl;
// Gerhard END
}
// Philippose - 23/02/2009
/* Special IGES File load function including the ability
to extract individual surface colours via the extended
OpenCascade XDE and XCAF Feature set.
*/
OCCGeometry *LoadOCC_IGES(const char *filename)
{
OCCGeometry *occgeo;
occgeo = new OCCGeometry;
// Initiate a dummy XCAF Application to handle the IGES XCAF Document
static Handle_XCAFApp_Application dummy_app = XCAFApp_Application::GetApplication();
// Create an XCAF Document to contain the IGES file itself
Handle_TDocStd_Document iges_doc;
// Check if a IGES File is already open under this handle, if so, close it to prevent
// Segmentation Faults when trying to create a new document
if(dummy_app->NbDocuments() > 0)
{
dummy_app->GetDocument(1,iges_doc);
dummy_app->Close(iges_doc);
}
dummy_app->NewDocument ("IGES-XCAF",iges_doc);
IGESCAFControl_Reader reader;
Standard_Integer stat = reader.ReadFile((char*)filename);
if(stat != IFSelect_RetDone)
{
throw NgException("Couldn't load occ");
}
// Enable transfer of colours
reader.SetColorMode(Standard_True);
reader.Transfer(iges_doc);
// Read in the shape(s) and the colours present in the IGES File
Handle_XCAFDoc_ShapeTool iges_shape_contents = XCAFDoc_DocumentTool::ShapeTool(iges_doc->Main());
Handle_XCAFDoc_ColorTool iges_colour_contents = XCAFDoc_DocumentTool::ColorTool(iges_doc->Main());
TDF_LabelSequence iges_shapes;
iges_shape_contents->GetShapes(iges_shapes);
// List out the available colours in the IGES File as Colour Names
TDF_LabelSequence all_colours;
iges_colour_contents->GetColors(all_colours);
PrintMessage(1,"Number of colours in IGES File: ",all_colours.Length());
for(int i = 1; i <= all_colours.Length(); i++)
{
Quantity_Color col;
stringstream col_rgb;
iges_colour_contents->GetColor(all_colours.Value(i),col);
col_rgb << " : (" << col.Red() << "," << col.Green() << "," << col.Blue() << ")";
PrintMessage(1, "Colour [", i, "] = ",col.StringName(col.Name()),col_rgb.str());
}
// For the IGES Reader, all the shapes can be exported as one compound shape
// using the "OneShape" member
occgeo->shape = reader.OneShape();
occgeo->face_colours = iges_colour_contents;
occgeo->changed = 1;
occgeo->BuildFMap();
occgeo->CalcBoundingBox();
PrintContents (occgeo);
return occgeo;
}
// Philippose - 29/01/2009
/* Special STEP File load function including the ability
to extract individual surface colours via the extended
OpenCascade XDE and XCAF Feature set.
*/
OCCGeometry * LoadOCC_STEP (const char * filename)
{
OCCGeometry * occgeo;
occgeo = new OCCGeometry;
LoadOCCInto(occgeo, filename);
return occgeo;
}
@ -1355,8 +1357,34 @@ void STEP_GetEntityName(const TopoDS_Shape & theShape, STEPCAFControl_Reader * a
}
}
void OCCGeometry :: DoArchive(Archive& ar)
{
if(ar.Output())
{
std::stringstream ss;
STEPControl_Writer writer;
writer.Transfer(shape, STEPControl_AsIs);
auto filename = ".tmpfile_out.step";
writer.Write(filename);
std::ifstream is(filename);
ss << is.rdbuf();
ar << ss.str();
std::remove(filename);
}
else
{
std::string str;
ar & str;
auto filename = ".tmpfile.step";
auto tmpfile = std::fopen(filename, "w");
std::fputs(str.c_str(), tmpfile);
std::fclose(tmpfile);
LoadOCCInto(this, filename);
std::remove(filename);
}
}
const char * shapesname[] =
{" ", "CompSolids", "Solids", "Shells",

View File

@ -246,6 +246,7 @@ namespace netgen
DLL_HEADER virtual void Save (string filename) const;
void DoArchive(Archive& ar);
DLL_HEADER void BuildFMap();

View File

@ -18,6 +18,23 @@ DLL_HEADER void ExportNgOCC(py::module &m)
{
py::class_<OCCGeometry, shared_ptr<OCCGeometry>, NetgenGeometry> (m, "OCCGeometry", R"raw_string(Use LoadOCCGeometry to load the geometry from a *.step file.)raw_string")
.def(py::init<>())
.def(py::pickle(
[](OCCGeometry& self)
{
auto ss = make_shared<stringstream>();
BinaryOutArchive archive(ss);
archive & self;
archive.FlushBuffer();
return py::make_tuple(py::bytes(ss->str()));
},
[](py::tuple state)
{
auto geo = make_shared<OCCGeometry>();
auto ss = make_shared<stringstream> (py::cast<py::bytes>(state[0]));
BinaryInArchive archive(ss);
archive & (*geo);
return geo;
}))
.def("Heal",[](OCCGeometry & self, double tolerance, bool fixsmalledges, bool fixspotstripfaces, bool sewfaces, bool makesolids, bool splitpartitions)
{
self.tolerance = tolerance;

View File

@ -20,6 +20,23 @@ DLL_HEADER void ExportSTL(py::module & m)
{
py::class_<STLGeometry,shared_ptr<STLGeometry>, NetgenGeometry> (m,"STLGeometry")
.def(py::init<>())
.def(py::pickle(
[](STLGeometry& self)
{
auto ss = make_shared<stringstream>();
BinaryOutArchive archive(ss);
archive & self;
archive.FlushBuffer();
return py::make_tuple(py::bytes(ss->str()));
},
[](py::tuple state)
{
auto geo = make_shared<STLGeometry>();
auto ss = make_shared<stringstream> (py::cast<py::bytes>(state[0]));
BinaryInArchive archive(ss);
archive & (*geo);
return geo;
}))
.def("_visualizationData", [](shared_ptr<STLGeometry> stl_geo)
{
std::vector<float> vertices;

View File

@ -3579,5 +3579,5 @@ void STLGeometry :: SmoothGeometry ()
STLInit stlinit;
static RegisterClassForArchive<STLGeometry, NetgenGeometry, STLTopology> stlgeo;
}

View File

@ -184,6 +184,10 @@ namespace netgen
STLGeometry();
virtual ~STLGeometry();
void DoArchive(Archive& ar)
{
STLTopology::DoArchive(ar);
}
void Clear();

View File

@ -1074,5 +1074,5 @@ void STLTopology :: OrientAfterTrig (int trig)
}
}
static RegisterClassForArchive<STLTopology> stltop;
}

View File

@ -96,6 +96,17 @@ public:
STLTriangle (const int * apts);
STLTriangle () {pts[0]=0;pts[1]=0;pts[2]=0;}
void DoArchive(Archive& ar)
{
ar.Do(&topedges[0],3);
ar.Do(&nbtrigs[0][0], 6);
ar.Do(&pts[0],3);
ar.Do(&domains[0],2);
size_t i = flags.toperror;
ar & normal & box & center & rad & facenum & i;
flags.toperror = i;
}
int operator[] (int i) const { return pts[i]; }
int & operator[] (int i) { return pts[i]; }
@ -279,6 +290,13 @@ public:
void Save (const char* filename) const;
void SaveBinary (const char* filename, const char* aname) const;
void SaveSTLE (const char * filename) const; // stores trigs and edges
virtual void DoArchive(Archive& ar)
{
ar & trias & points & boundingbox & pointtol;
if(ar.Input())
FindNeighbourTrigs();
}
virtual void InitSTLGeometry (const Array<STLReadTriangle> & readtrigs);

View File

@ -1,8 +1,8 @@
import netgen.csg as csg
import pickle, numpy
def test_pickle_csg():
import netgen.csg as csg
geo = csg.CSGeometry()
geo.Add(csg.Sphere(csg.Pnt(0,0,0), 2).bc("sphere"))
brick = csg.OrthoBrick(csg.Pnt(-3,-3,-3), csg.Pnt(3,3,3))
@ -35,5 +35,51 @@ def test_pickle_csg():
for val1, val2 in zip(vd1.values(), vd2.values()):
assert numpy.array_equal(val1, val2)
def test_pickle_stl():
import netgen.stl as stl
geo = stl.LoadSTLGeometry("../../tutorials/hinge.stl")
geo_dump = pickle.dumps(geo)
geo2 = pickle.loads(geo_dump)
vd1 = geo._visualizationData()
vd2 = geo2._visualizationData()
for val1, val2 in zip(vd1.values(), vd2.values()):
assert numpy.array_equal(val1, val2)
def test_pickle_occ():
import netgen.NgOCC as occ
geo = occ.LoadOCCGeometry("../../tutorials/frame.step")
geo_dump = pickle.dumps(geo)
geo2 = pickle.loads(geo_dump)
vd1 = geo._visualizationData()
vd2 = geo2._visualizationData()
# TODO: it looks fine, but tests fail, so I assume we loose some info?
# for val1, val2 in zip(vd1.values(), vd2.values()):
# assert numpy.allclose(val1, val2, rtol=0.01)
def test_pickle_geom2d():
import netgen.geom2d as geom2d
geo = geom2d.SplineGeometry()
# point coordinates ...
pnts = [ (0,0), (1,0), (1,0.6), (0,0.6), \
(0.2,0.6), (0.8,0.6), (0.8,0.8), (0.2,0.8), \
(0.5,0.15), (0.65,0.3), (0.5,0.45), (0.35,0.3) ]
pnums = [geo.AppendPoint(*p) for p in pnts]
# start-point, end-point, boundary-condition, domain on left side, domain on right side:
lines = [ (0,1,1,1,0), (1,2,2,1,0), (2,5,2,1,0), (5,4,2,1,2), (4,3,2,1,0), (3,0,2,1,0), \
(5,6,2,2,0), (6,7,2,2,0), (7,4,2,2,0), \
(8,9,2,3,1), (9,10,2,3,1), (10,11,2,3,1), (11,8,2,3,1) ]
for p1,p2,bc,left,right in lines:
geo.Append( ["line", pnums[p1], pnums[p2]], bc=bc, leftdomain=left, rightdomain=right)
geo_dump = pickle.dumps(geo)
geo2 = pickle.loads(geo_dump)
vd1 = geo._visualizationData()
vd2 = geo2._visualizationData()
for val1, val2 in zip(vd1.values(), vd2.values()):
assert numpy.array_equal(val1, val2)
if __name__ == "__main__":
test_pickle_csg()