Merge branch 'save_occ_to_mesh' into 'master'

Save OCCGeometry in mesh file using TextOutArchive

See merge request jschoeberl/netgen!450
This commit is contained in:
Joachim Schöberl 2021-11-12 13:15:50 +00:00
commit 9477fb0321
11 changed files with 185 additions and 50 deletions

View File

@ -9,6 +9,7 @@
#include <functional> // for function
#include <map> // for map
#include <memory> // for shared_ptr
#include <optional> // for optional
#include <string> // for string
#include <type_traits> // for declval, enable_if_t, false_type, is_co...
#include <cstddef> // for std::byte
@ -290,6 +291,24 @@ namespace ngcore
}
return (*this);
}
template<typename T>
Archive& operator& (std::optional<T>& opt)
{
bool has_value = opt.has_value();
(*this) & has_value;
if(has_value)
{
if(Output())
(*this) << *opt;
else
{
T value;
(*this) & value;
opt = value;
}
}
return (*this);
}
// Archive arrays =====================================================
// this functions can be overloaded in Archive implementations for more efficiency
template <typename T, typename = std::enable_if_t<is_archivable<T>>>

View File

@ -1620,7 +1620,7 @@ namespace netgen
{
public:
virtual NetgenGeometry * Load (string filename) const;
virtual NetgenGeometry * LoadFromMeshFile (istream & ist) const;
virtual NetgenGeometry * LoadFromMeshFile (istream & ist, string token) const;
// virtual VisualScene * GetVisualScene (const NetgenGeometry * geom) const;
};
@ -1659,22 +1659,14 @@ namespace netgen
return NULL;
}
NetgenGeometry * CSGeometryRegister :: LoadFromMeshFile (istream & ist) const
NetgenGeometry * CSGeometryRegister :: LoadFromMeshFile (istream & ist, string token) const
{
string auxstring;
if (ist.good())
{
ist >> auxstring;
if (auxstring == "csgsurfaces")
{
CSGeometry * geometry = new CSGeometry ("");
geometry -> LoadSurfaces(ist);
return geometry;
}
// else
// ist.putback (auxstring);
}
return NULL;
if (token != "csgsurfaces")
return nullptr;
CSGeometry * geometry = new CSGeometry ("");
geometry -> LoadSurfaces(ist);
return geometry;
}

View File

@ -269,6 +269,11 @@ namespace netgen
CalcInverse (*this, inv);
sol = inv * rhs;
}
void DoArchive(Archive & ar)
{
ar.Do(x, H*W);
}
};

View File

@ -133,6 +133,11 @@ public:
Mat<D> & GetMatrix() { return m; }
Vec<D> & GetVector() { return v; }
void DoArchive(Archive& ar)
{
ar & m & v;
}
///
Transformation CalcInverse () const
{

View File

@ -104,15 +104,8 @@ void Ng_LoadMeshFromStream ( istream & input )
mesh -> Load(input);
SetGlobalMesh (mesh);
for (int i = 0; i < geometryregister.Size(); i++)
{
NetgenGeometry * hgeom = geometryregister[i]->LoadFromMeshFile (input);
if (hgeom)
{
ng_geometry.reset (hgeom);
break;
}
}
ng_geometry = geometryregister.LoadFromMeshFile (input);
if (!ng_geometry)
ng_geometry = make_shared<NetgenGeometry>();
mesh->SetGeometry (ng_geometry);

View File

@ -507,9 +507,27 @@ namespace netgen
shared_ptr<NetgenGeometry> GeometryRegisterArray :: LoadFromMeshFile (istream & ist) const
{
if (!ist.good())
return nullptr;
string token;
ist >> token;
if(token == "TextOutArchive")
{
NetgenGeometry *geo = nullptr;
size_t string_length;
ist >> string_length;
string buffer(string_length+1, '\0');
ist.read(&buffer[0], string_length);
auto ss = make_shared<stringstream>(buffer);
TextInArchive in(ss);
in & geo;
return shared_ptr<NetgenGeometry>(geo);
}
for (int i = 0; i < Size(); i++)
{
NetgenGeometry * hgeom = (*this)[i]->LoadFromMeshFile (ist);
NetgenGeometry * hgeom = (*this)[i]->LoadFromMeshFile (ist, token);
if (hgeom)
return shared_ptr<NetgenGeometry>(hgeom);
}

View File

@ -224,7 +224,7 @@ namespace netgen
public:
virtual ~GeometryRegister();
virtual NetgenGeometry * Load (string filename) const = 0;
virtual NetgenGeometry * LoadFromMeshFile (istream & /* ist */) const { return NULL; }
virtual NetgenGeometry * LoadFromMeshFile (istream & /* ist */, string) const { return NULL; }
virtual class VisualScene * GetVisualScene (const NetgenGeometry * /* geom */) const
{ return NULL; }
virtual void SetParameters (Tcl_Interp * /* interp */) { ; }

View File

@ -1654,31 +1654,108 @@ namespace netgen
}
}
void OCCGeometry :: SaveToMeshFile (ostream & ost) const
{
auto ss = make_shared<stringstream>();
TextOutArchive out(ss);
NetgenGeometry *geo = const_cast<OCCGeometry*>(this);
out & geo;
ost << "TextOutArchive" << endl;
ost << ss->str().size() << endl;
ost << ss->str();
}
void OCCGeometry :: DoArchive(Archive& ar)
{
constexpr int current_format_version = 0;
int format_version = current_format_version;
auto netgen_version = GetLibraryVersion("netgen");
ar & netgen_version & format_version;
if(ar.Output())
{
std::stringstream ss;
STEPControl_Writer writer;
writer.Transfer(shape, STEPControl_AsIs);
auto filename = GetTempFilename();
writer.Write(filename.c_str());
std::ifstream is(filename.c_str());
ss << is.rdbuf();
BRepTools::Write(shape, ss);
ar << ss.str();
std::remove(filename.c_str());
}
else
{
if(format_version>current_format_version)
throw Exception("Loading OCCGeometry from archive: unkown format version "
+ ToString(format_version)
+ ", written by netgen version "
+ ToString(netgen_version));
std::string str;
ar & str;
stringstream ss(str);
BRep_Builder builder;
BRepTools::Read(shape, ss, builder);
}
auto filename = GetTempFilename();
auto tmpfile = std::fopen(filename.c_str(), "w");
std::fputs(str.c_str(), tmpfile);
std::fclose(tmpfile);
LoadOCCInto(this, filename.c_str());
std::remove(filename.c_str());
// enumerate shapes and archive only integers
auto my_hash = [](const TopoDS_Shape & key) {
auto occ_hash = key.HashCode(1<<31UL);
return std::hash<decltype(occ_hash)>()(occ_hash);
};
std::unordered_map<TopoDS_Shape, int, decltype(my_hash)> shape_map(10, my_hash);
Array<TopoDS_Shape> shape_list;
std::map<Handle(TopoDS_TShape), int> tshape_map;
Array<Handle(TopoDS_TShape)> tshape_list;
ar & occdim;
for (auto typ : { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE })
for (TopExp_Explorer e(shape, typ); e.More(); e.Next())
{
auto ds = e.Current();
auto ts = ds.TShape();
if(shape_map.count(ds)==0)
{
shape_map[ds] = shape_list.Size();
shape_list.Append(ds);
}
if(tshape_map.count(ts)==0)
{
tshape_map[ts] = shape_list.Size();
tshape_list.Append(ts);
}
}
for (auto ts : tshape_list)
{
bool has_properties = global_shape_properties.count(ts);
ar & has_properties;
if(has_properties)
ar & global_shape_properties[ts];
bool has_identifications = identifications.count(ts);
ar & has_identifications;
if(has_identifications)
{
auto & idents = identifications[ts];
auto n_idents = idents.size();
ar & n_idents;
idents.resize(n_idents);
for(auto i : Range(n_idents))
{
auto & id = idents[i];
int shape_id;
if(ar.Output())
shape_id = shape_map[id.other];
ar & shape_id & id.trafo & id.inverse & id.name;
if(ar.Input())
id.other = shape_list[shape_id];
}
}
}
if(ar.Input())
{
changed = 1;
BuildFMap();
CalcBoundingBox();
}
}

View File

@ -232,6 +232,11 @@ namespace netgen
if (prop2.col) col = prop2.col;
maxh = min2(maxh, prop2.maxh);
}
void DoArchive(Archive& ar)
{
ar & name & col & maxh & hpref;
}
};
@ -375,6 +380,7 @@ namespace netgen
void FinalizeMesh(Mesh& mesh) const override;
void Save (string filename) const override;
void SaveToMeshFile (ostream & /* ost */) const override;
void DoArchive(Archive& ar) override;

View File

@ -233,16 +233,10 @@ namespace netgen
MyMPI_SendCmd ("mesh");
mesh -> Distribute();
#endif
for (int i = 0; i < geometryregister.Size(); i++)
{
NetgenGeometry * hgeom = geometryregister[i]->LoadFromMeshFile (*infile);
if (hgeom)
{
ng_geometry = shared_ptr<NetgenGeometry>(hgeom);
break;
}
}
delete infile;
auto geo = geometryregister.LoadFromMeshFile (*infile);
if(geo)
ng_geometry = geo;
delete infile;
/*
string auxstring;

View File

@ -265,6 +265,28 @@ void testEnum(Archive& in, Archive& out)
CHECK(enin == CASE2);
}
void testOptional(Archive& in, Archive& out)
{
{
std::optional<int> no_value;
std::optional<int> myint = 42;
std::optional<string> mystr = "have an optional string";
out & no_value & myint & mystr;
out.FlushBuffer();
}
{
std::optional<int> no_value_;
std::optional<int> myint_;
std::optional<string> mystr_;
in & no_value_ & myint_ & mystr_;
CHECK(no_value_.has_value() == false);
CHECK(myint_.has_value() == true);
CHECK(*myint_ == 42);
CHECK(mystr_.has_value() == true);
CHECK(*mystr_ == "have an optional string");
}
}
void testArchive(Archive& in, Archive& out)
{
SECTION("Empty String")
@ -322,6 +344,10 @@ void testArchive(Archive& in, Archive& out)
{
testEnum(in, out);
}
SECTION("optional")
{
testOptional(in, out);
}
}
TEST_CASE("BinaryArchive")