cgal/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp

605 lines
17 KiB
C++

#include <CGAL/SMDS_3/io_signature.h>
#include "Scene_c3t3_item.h"
#include <CGAL/SMDS_3/tet_soup_to_c3t3.h>
#include <CGAL/Three/Polyhedron_demo_io_plugin_interface.h>
#include <CGAL/Three/Three.h>
#include <CGAL/IO/File_avizo.h>
#include <iostream>
#include <fstream>
#include <QMessageBox>
class Polyhedron_demo_c3t3_binary_io_plugin :
public QObject,
public CGAL::Three::Polyhedron_demo_io_plugin_interface
{
Q_OBJECT
Q_INTERFACES(CGAL::Three::Polyhedron_demo_io_plugin_interface)
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.IOPluginInterface/1.90" FILE "c3t3_io_plugin.json")
public:
QString name() const override { return "C3t3_io_plugin"; }
QString nameFilters() const override { return "binary files (*.cgal);;ascii (*.mesh);;maya (*.ma);;avizo (*.tetra.am)"; }
QString saveNameFilters() const override{
return "binary files (*.cgal);;ascii (*.mesh);;maya (*.ma);;avizo (*.tetra.am);;OFF files (*.off)"; }
QString loadNameFilters() const override {
return "binary files (*.cgal);;ascii (*.mesh);;avizo (*.tetra.am)"; }
bool canLoad(QFileInfo) const override;
QList<Scene_item*> load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true) override;
bool canSave(const CGAL::Three::Scene_item*) override;
bool save(QFileInfo fileinfo,QList<CGAL::Three::Scene_item*>& ) override;
bool isDefaultLoader(const Scene_item* item) const override{
if(qobject_cast<const Scene_c3t3_item*>(item))
return true;
return false;
}
private:
bool try_load_other_binary_format(std::istream& in, C3t3& c3t3);
bool try_load_a_cdt_3(std::istream& in, C3t3& c3t3);
void update_c3t3(C3t3& c3t3);
};
bool Polyhedron_demo_c3t3_binary_io_plugin::canLoad(QFileInfo fi) const {
if(!fi.suffix().contains("cgal"))
return true;
std::ifstream in(fi.filePath().toUtf8(),
std::ios_base::in|std::ios_base::binary);
if(!in) {
std::cerr << "Error! Cannot open file "
<< (const char*)fi.filePath().toUtf8() << std::endl;
return false;
}
if (fi.suffix().toLower() == "cgal")
{
std::string line;
std::istringstream iss;
std::getline(in, line);
iss.str(line);
std::string keyword;
if (iss >> keyword)
if (keyword == "binary")
return true;
}
else if (fi.suffix().toLower() == "am")
{
return true;
}
return false;
}
QList<Scene_item*>
Polyhedron_demo_c3t3_binary_io_plugin::load(
QFileInfo fileinfo, bool& ok, bool add_to_scene) {
// Open file
ok = true;
std::ifstream in(fileinfo.filePath().toUtf8(),
std::ios_base::in|std::ios_base::binary);
if(!in) {
std::cerr << "Error! Cannot open file "
<< (const char*)fileinfo.filePath().toUtf8() << std::endl;
ok = false;
return QList<Scene_item*>();
}
Scene_c3t3_item* item = new Scene_c3t3_item();
if(fileinfo.size() == 0)
{
CGAL::Three::Three::warning( tr("The file you are trying to load is empty."));
item->setName(fileinfo.completeBaseName());
if(add_to_scene)
CGAL::Three::Three::scene()->addItem(item);
return QList<Scene_item*>()<< item;
}
if(fileinfo.suffix().toLower() == "cgal")
{
item->setName(fileinfo.baseName());
if(item->load_binary(in)) {
if(add_to_scene){
item->resetCutPlane();
CGAL::Three::Three::scene()->addItem(item);
}
return QList<Scene_item*>() << item;
}
item->c3t3().clear();
in.seekg(0);
if(try_load_other_binary_format(in, item->c3t3())) {
item->resetCutPlane();
item->c3t3_changed();
item->changed();
if(add_to_scene)
CGAL::Three::Three::scene()->addItem(item);
return QList<Scene_item*>()<< item;
}
item->c3t3().clear();
in.seekg(0);
if(try_load_a_cdt_3(in, item->c3t3())) {
item->resetCutPlane();
item->c3t3_changed();
item->changed();
if(add_to_scene)
CGAL::Three::Three::scene()->addItem(item);
return QList<Scene_item*>()<<item;
}
}
else if (fileinfo.suffix().toLower() == "mesh")
{
in.close();
in.open(fileinfo.filePath().toUtf8(), std::ios_base::in);//not binary
CGAL_assertion(!(!in));
item->setName(fileinfo.baseName());
item->set_valid(false);
if(CGAL::SMDS_3::build_triangulation_from_file(in, item->c3t3().triangulation(),
/*verbose = */false, /*replace_subdomain_0 = */false, /*allow_non_manifold = */true))
{
update_c3t3(item->c3t3());
item->resetCutPlane();
item->c3t3_changed();
if(add_to_scene)
CGAL::Three::Three::scene()->addItem(item);
return QList<Scene_item*>()<<item;
}
else if(item->c3t3().triangulation().number_of_finite_cells() == 0)
{
QMessageBox::warning((QWidget*)NULL, tr("C3t3_io_plugin"),
tr("No finite cell provided.\n"
"Nothing to display."),
QMessageBox::Ok);
}
}
else if (fileinfo.suffix().toLower() == "am")
{
if (CGAL::IO::internal::is_avizo_tetra_format(in, "ascii"))
{
in.close();
in.open(fileinfo.filePath().toUtf8(), std::ios_base::in);//not binary
CGAL_assertion(!(!in));
}
item->setName(fileinfo.baseName());
if (CGAL::IO::read_AVIZO_TETRA(in, item->c3t3().triangulation()))
{
update_c3t3(item->c3t3());
item->resetCutPlane();
item->c3t3_changed();
if (add_to_scene)
CGAL::Three::Three::scene()->addItem(item);
return QList<Scene_item*>() << item;
}
}
// if all loading failed...
delete item;
ok = false;
return QList<Scene_item*>();
}
bool Polyhedron_demo_c3t3_binary_io_plugin::canSave(const CGAL::Three::Scene_item* item)
{
// This plugin supports c3t3 items.
return qobject_cast<const Scene_c3t3_item*>(item);
}
bool
Polyhedron_demo_c3t3_binary_io_plugin::
save(QFileInfo fileinfo, QList<Scene_item *> &items)
{
Scene_item* item = items.front();
if(!qobject_cast<Scene_c3t3_item*>(item)->is_valid())
{
QMessageBox::warning(CGAL::Three::Three::mainWindow(), "", "The c3t3_item is not valid. You cannot save it.");
return false;
}
const Scene_c3t3_item* c3t3_item = qobject_cast<const Scene_c3t3_item*>(item);
if ( NULL == c3t3_item )
{
return false;
}
QString path = fileinfo.absoluteFilePath();
if(path.endsWith(".cgal"))
{
std::ofstream out(fileinfo.filePath().toUtf8(),
std::ios_base::out|std::ios_base::binary);
bool ok = out && c3t3_item->save_binary(out);
if(!ok)
return false;
else
{
items.pop_front();
return true;
}
}
else if (fileinfo.suffix() == "mesh")
{
std::ofstream medit_file (qPrintable(path));
CGAL::IO::write_MEDIT(medit_file, c3t3_item->c3t3(),
CGAL::parameters::rebind_labels(true)
.show_patches(true));
items.pop_front();
return true;
}
else if (fileinfo.suffix() == "ma")
{
std::ofstream maya_file (qPrintable(path));
c3t3_item->c3t3().output_to_maya(
maya_file,true);
items.pop_front();
return true;
}
else if (fileinfo.suffix() == "am")
{
std::ofstream avizo_file (qPrintable(path));
CGAL::IO::output_to_avizo(avizo_file, c3t3_item->c3t3());
items.pop_front();
return true;
}
else if (fileinfo.suffix() == "off")
{
std::ofstream off_file(qPrintable(path));
c3t3_item->c3t3().output_facets_in_complex_to_off(off_file);
items.pop_front();
return true;
}
else
return false;
}
struct Fake_mesh_domain {
typedef CGAL::Tag_true Has_features;
typedef int Subdomain_index;
typedef std::pair<int,int> Surface_patch_index;
typedef int Curve_index;
typedef int Corner_index;
typedef boost::variant<Subdomain_index,Surface_patch_index> Index;
};
typedef Geom_traits Fake_gt;
typedef CGAL::Mesh_vertex_base_3<Fake_gt, Fake_mesh_domain> Fake_vertex_base;
typedef CGAL::Compact_mesh_cell_base_3<Fake_gt, Fake_mesh_domain> Fake_cell_base;
typedef CGAL::Triangulation_data_structure_3<Fake_vertex_base,Fake_cell_base> Fake_tds;
typedef CGAL::Regular_triangulation_3<Fake_gt, Fake_tds> Fake_tr;
typedef CGAL::Mesh_complex_3_in_triangulation_3<
Fake_tr,
Fake_mesh_domain::Corner_index,
Fake_mesh_domain::Curve_index> Fake_c3t3;
template <class Vb = CGAL::Triangulation_vertex_base_3<EPICK> >
struct Fake_CDT_3_vertex_base : public Vb
{
typedef Vb Base;
bool steiner;
std::size_t ref_1, ref_2;
template < typename TDS2 >
struct Rebind_TDS {
typedef typename Base::template Rebind_TDS<TDS2>::Other Vb2;
typedef Fake_CDT_3_vertex_base<Vb2> Other;
};
};
template <class Vb>
std::istream&
operator>>( std::istream& is, Fake_CDT_3_vertex_base<Vb>& v)
{
is >> static_cast<typename Fake_CDT_3_vertex_base<Vb>::Base&>(v);
char s;
if( CGAL::IO::is_ascii(is) ) {
is >> s;
if( s == 'S' ) {
v.steiner = true;
is >> v.ref_1 >> v.ref_2;
}
else {
CGAL_assertion(s == '.' || s == 'F');
v.steiner = false;
}
} else {
CGAL::read( is, s );
if(is.bad()) return is;
if( s == 'S' ) {
v.steiner = true;
CGAL::read( is, v.ref_1 );
CGAL::read( is, v.ref_2 );
}
else {
// if(s != '.') {
// std::cerr << "v.point()=" << v.point() << std::endl;
// std::cerr << "s=" << s << " (" << (int)s
// << "), just before position "
// << is.tellg() << " !\n";
// }
CGAL_assertion(s == '.' || s== 'F');
v.steiner = false;
}
}
return is;
}
template <class Cb = CGAL::Triangulation_cell_base_3<EPICK> >
struct Fake_CDT_3_cell_base : public Cb
{
typedef Cb Base;
int constrained_facet[4];
bool _restoring[6];
int to_edge_index( int li, int lj ) const {
CGAL_precondition( li >= 0 && li < 4 );
CGAL_precondition( lj >= 0 && lj < 4 );
CGAL_precondition( li != lj );
return ( li==0 || lj==0 ) ? li+lj-1 : li+lj;
}
template < typename TDS2 >
struct Rebind_TDS {
typedef typename Base::template Rebind_TDS<TDS2>::Other Cb2;
typedef Fake_CDT_3_cell_base<Cb2> Other;
};
};
template <typename Cb>
std::istream&
operator>>( std::istream& is, Fake_CDT_3_cell_base<Cb>& c) {
char s;
for( int li = 0; li < 4; ++li ) {
if( CGAL::IO::is_ascii(is) )
is >> c.constrained_facet[li];
else
CGAL::read( is, c.constrained_facet[li] );
}
if( CGAL::IO::is_ascii(is) ) {
is >> s;
CGAL_assertion(s == '-');
}
is >> static_cast<typename Fake_CDT_3_cell_base<Cb>::Base&>(c);
for( int li = 0; li < 3; ++li ) {
for( int lj = li+1; lj < 4; ++lj ) {
char s;
is >> s;
if(s == 'C') {
c._restoring[c.to_edge_index(li, lj)] = true;
} else {
if(s != '.') {
std::cerr << "cDT cell:";
for( int li = 0; li < 4; ++li ) {
std::cerr << " " << c.constrained_facet[li];
}
std::cerr << "\n";
std::cerr << "s=" << s << " (" << (int)s
<< "), just before position "
<< is.tellg() << " !\n"; }
CGAL_assertion(s == '.');
c._restoring[c.to_edge_index(li, lj)] = false;
}
}
}
return is;
}
typedef CGAL::Triangulation_data_structure_3<Fake_CDT_3_vertex_base<>, Fake_CDT_3_cell_base<> > Fake_CDT_3_TDS;
typedef CGAL::Triangulation_3<EPICK, Fake_CDT_3_TDS> Fake_CDT_3;
typedef Fake_mesh_domain::Surface_patch_index Fake_patch_id;
template <typename Tr1, typename Tr2>
struct Update_vertex
{
typedef Fake_mesh_domain::Surface_patch_index Sp_index;
typedef typename Tr1::Vertex V1;
typedef typename Tr2::Vertex V2;
typedef typename Tr2::Point Point;
V2 operator()(const V1&)
{
return V2();
}
bool operator()(const V1& v1, V2& v2)
{
v2.set_point(Point(v1.point()));
v2.set_dimension(v1.in_dimension());
v2.set_special(v1.is_special());
switch(v1.in_dimension()) {
case 2:
{
const typename V1::Index& index = v1.index();
const Sp_index sp_index = boost::get<Sp_index>(index);
v2.set_index((std::max)(sp_index.first, sp_index.second));
}
break;
default:// -1, 0, 1, 3
v2.set_index(boost::get<int>(v1.index()));
}
return true;
}
}; // end struct Update_vertex
struct Update_cell {
typedef Fake_mesh_domain::Surface_patch_index Sp_index;
template <typename C1, typename C2>
bool operator()(const C1& c1, C2& c2) {
c2.set_subdomain_index(c1.subdomain_index());
for(int i = 0; i < 4; ++i) {
const Sp_index sp_index = c1.surface_patch_index(i);
c2.set_surface_patch_index(i, (std::max)(sp_index.first,
sp_index.second));
CGAL_assertion(c1.is_facet_on_surface(i) ==
c2.is_facet_on_surface(i));
}
return true;
}
}; // end struct Update_cell
template <typename Tr1, typename Tr2>
struct Update_vertex_from_CDT_3 {
// Tr1 and Tr2's point types might be different
typedef typename Tr1::Vertex V1;
typedef typename Tr2::Vertex V2;
typedef typename Tr2::Point Point;
V2 operator()(const V1&)
{
return V2();
}
void operator()(const V1& v1, V2& v2)
{
v2.set_point(Point(v1.point()));
v2.set_dimension(2);
v2.set_special(false);
}
}; // end struct Update_vertex
struct Update_cell_from_CDT_3 {
typedef Fake_mesh_domain::Surface_patch_index Sp_index;
template <typename C1,typename C2>
void operator()(const C1& c1, C2& c2) {
c2.set_subdomain_index(1);
for(int i = 0; i < 4; ++i) {
c2.set_surface_patch_index(i, c1.constrained_facet[i]);
}
}
}; // end struct Update_cell
bool
Polyhedron_demo_c3t3_binary_io_plugin::
try_load_a_cdt_3(std::istream& is, C3t3& c3t3)
{
std::cerr << "Try load a CDT_3...";
std::string s;
if(!(is >> s)) return false;
bool binary = (s == "binary");
if(binary) {
if(!(is >> s)) return false;
}
if (s != "CGAL" ||
!(is >> s) ||
s != "c3t3")
{
return false;
}
std::getline(is, s);
if(s != "") {
if(s != std::string(" ") + CGAL::Get_io_signature<Fake_CDT_3>()()) {
std::cerr << "load_binary_file:"
<< "\n expected format: " << CGAL::Get_io_signature<Fake_CDT_3>()()
<< "\n got format:" << s << std::endl;
return false;
}
}
if(binary) CGAL::IO::set_binary_mode(is);
if(c3t3.triangulation().file_input<
Fake_CDT_3,
Update_vertex_from_CDT_3<Fake_CDT_3, C3t3::Triangulation>,
Update_cell_from_CDT_3>(is))
{
c3t3.rescan_after_load_of_triangulation();
std::cerr << "Try load a CDT_3... DONE";
return true;
}
else {
return false;
}
}
void
Polyhedron_demo_c3t3_binary_io_plugin::
update_c3t3(C3t3& c3t3)
{
using Cell_handle = C3t3::Triangulation::Cell_handle;
c3t3.rescan_after_load_of_triangulation(); //fix counters for facets and cells
for (Cell_handle cit : c3t3.triangulation().finite_cell_handles())
{
CGAL_assertion(cit->subdomain_index() >= 0);
if (cit->subdomain_index() != C3t3::Triangulation::Cell::Subdomain_index())
c3t3.add_to_complex(cit, cit->subdomain_index());
for (int i = 0; i < 4; ++i)
{
if (cit->surface_patch_index(i) > 0)
c3t3.add_to_complex(cit, i, cit->surface_patch_index(i));
}
}
//if there is no facet in the complex, we add the border facets.
if (c3t3.number_of_facets_in_complex() == 0)
{
for (C3t3::Facet fit : c3t3.triangulation().finite_facets())
{
Cell_handle c = fit.first;
Cell_handle nc = c->neighbor(fit.second);
// By definition, Subdomain_index() is supposed to be the id of the exterior
if (c->subdomain_index() != C3t3::Triangulation::Cell::Subdomain_index() &&
nc->subdomain_index() == C3t3::Triangulation::Cell::Subdomain_index())
{
// Color the border facet with the index of its cell
c3t3.add_to_complex(c, fit.second, c->subdomain_index());
}
}
}
}
//Generates a compilation error.
bool
Polyhedron_demo_c3t3_binary_io_plugin::
try_load_other_binary_format(std::istream& is, C3t3& c3t3)
{
CGAL::IO::set_ascii_mode(is);
std::string s;
if(!(is >> s)) return false;
bool binary = false;
if(s == "binary") {
binary = true;
if(!(is >> s)) return false;
}
if( s != "CGAL" ||
!(is >> s) ||
s != "c3t3")
{
return false;
}
std::getline(is, s);
if(s != "") {
if(s != std::string(" ") + CGAL::Get_io_signature<Fake_c3t3>()()) {
std::cerr << "Polyhedron_demo_c3t3_binary_io_plugin::try_load_other_binary_format:"
<< "\n expected format: " << CGAL::Get_io_signature<Fake_c3t3>()()
<< "\n got format:" << s << std::endl;
return false;
}
}
if(binary) CGAL::IO::set_binary_mode(is);
else CGAL::IO::set_ascii_mode(is);
std::istream& f_is = c3t3.triangulation().file_input<
Fake_c3t3::Triangulation,
Update_vertex<Fake_c3t3::Triangulation, C3t3::Triangulation>,
Update_cell>(is);
c3t3.rescan_after_load_of_triangulation();
return f_is.good();
}
#include <QtPlugin>
#include "C3t3_io_plugin.moc"