cgal/Polyhedron/demo/Polyhedron/Plugins/IO/Polylines_io_plugin.cpp

392 lines
14 KiB
C++

#include "Scene_polylines_item.h"
#include <QMainWindow>
#include <CGAL/Three/Polyhedron_demo_io_plugin_interface.h>
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
#include <CGAL/Three/Polyhedron_demo_plugin_helper.h>
#include <CGAL/Polygon_mesh_processing/internal/simplify_polyline.h>
#include <CGAL/boost/graph/split_graph_into_polylines.h>
#include <CGAL/Mesh_3/polylines_to_protect.h>
#include <CGAL/Three/Three.h>
#include <fstream>
#include <QVariant>
#include <QMessageBox>
#include <QInputDialog>
using namespace CGAL::Three;
class Polyhedron_demo_polylines_io_plugin :
public QObject,
public Polyhedron_demo_io_plugin_interface,
public Polyhedron_demo_plugin_helper
{
Q_OBJECT
Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface CGAL::Three::Polyhedron_demo_io_plugin_interface)
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0" FILE "polylines_io_plugin.json")
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.IOPluginInterface/1.90")
public:
// To silent a warning -Woverloaded-virtual
// See https://stackoverflow.com/questions/9995421/gcc-woverloaded-virtual-warnings
using Polyhedron_demo_io_plugin_interface::init;
//! Configures the widget
void init(QMainWindow* mainWindow,
CGAL::Three::Scene_interface* scene_interface,
Messages_interface*) override{
//get the references
this->scene = scene_interface;
this->mw = mainWindow;
//creates and link the actions
actionJoin_polylines= new QAction(tr("Join Selected Polylines"), mainWindow);
actionJoin_polylines->setProperty("subMenuName", "Operations on Polylines");
actionJoin_polylines->setObjectName("actionJoinPolylines");
actionSplit_polylines= new QAction(tr("Split Selected Polylines"), mainWindow);
actionSplit_polylines->setProperty("subMenuName", "Operations on Polylines");
actionSplit_polylines->setObjectName("actionSplitPolylines");
actionSplit_polylines_graph= new QAction(tr("Split Graph into Polylines"), mainWindow);
actionSplit_polylines_graph->setProperty("subMenuName", "Operations on Polylines");
actionSplit_polylines_graph->setObjectName("actionSplitPolylinesGraph");
actionSimplify_polylines = new QAction(tr("Simplify Selected Polyline"), mainWindow);
actionSimplify_polylines->setProperty("subMenuName", "Operations on Polylines");
actionSimplify_polylines->setObjectName("actionSimplifyPolylines");
connect(actionSplit_polylines, &QAction::triggered, this, &Polyhedron_demo_polylines_io_plugin::split);
connect(actionSplit_polylines_graph, &QAction::triggered, this, &Polyhedron_demo_polylines_io_plugin::split_graph);
connect(actionJoin_polylines, &QAction::triggered, this, &Polyhedron_demo_polylines_io_plugin::join);
connect(actionSimplify_polylines, &QAction::triggered, this, &Polyhedron_demo_polylines_io_plugin::simplify);
}
QString name() const override{ return "polylines_io_plugin"; }
QString nameFilters() const override{ return "Polylines files (*.polylines.txt);; CGAL Polylines files (*.cgal)"; }
bool canLoad(QFileInfo fileinfo) 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 applicable(QAction* a) const override{
if( a == actionSimplify_polylines || a == actionSplit_polylines_graph)
return qobject_cast<Scene_polylines_item*>(scene->item(
scene->mainSelectionIndex()));
bool all_polylines_selected = true;
for(int index : scene->selectionIndices())
{
if (!qobject_cast<Scene_polylines_item*>(scene->item(index)))
{
all_polylines_selected = false;
}
}
if(a==actionSplit_polylines)
return (all_polylines_selected &&
scene->selectionIndices().size() == 1);
else if(a==actionJoin_polylines)
return (all_polylines_selected &&
scene->selectionIndices().size() > 1);
else
return false;
}
QList<QAction*> actions() const override{
return QList<QAction*>()<<actionSplit_polylines
<<actionJoin_polylines
<<actionSimplify_polylines
<<actionSplit_polylines_graph;
}
bool isDefaultLoader(const Scene_item* item) const override{
if(qobject_cast<const Scene_polylines_item*>(item))
return true;
return false;
}
protected Q_SLOTS:
//!Splits the selected Scene_polylines_item in multiple items all containing a single polyline.
void split();
void split_graph();
//!Joins the selected Scene_polylines_items in a single item containing all their polylines.
void join();
void simplify();
private:
QAction* actionSplit_polylines;
QAction* actionSplit_polylines_graph;
QAction* actionJoin_polylines;
QAction* actionSimplify_polylines;
};
bool Polyhedron_demo_polylines_io_plugin::canLoad(QFileInfo fileinfo) const{
if(!fileinfo.suffix().contains("cgal"))
return true;
std::ifstream in(fileinfo.filePath().toUtf8());
if(!in) {
return false;
}
int first;
if(!(in >> first)
|| first <= 0)
return false;
return true;
}
QList<Scene_item*>
Polyhedron_demo_polylines_io_plugin::
load(QFileInfo fileinfo, bool& ok, bool add_to_scene){
// Open file
std::ifstream ifs(fileinfo.filePath().toUtf8());
if(!ifs) {
std::cerr << "Error! Cannot open file " << (const char*)fileinfo.filePath().toUtf8() << std::endl;
ok = false;
return QList<Scene_item*>();
}
if(fileinfo.size() == 0)
{
CGAL::Three::Three::warning( tr("The file you are trying to load is empty."));
Scene_polylines_item* item = new Scene_polylines_item;
item->setName(fileinfo.completeBaseName());
ok = true;
if(add_to_scene)
CGAL::Three::Three::scene()->addItem(item);
return QList<Scene_item*>()<<item;
}
std::list<std::vector<Scene_polylines_item::Point_3> > polylines;
QStringList polylines_metadata;
int counter = 0;
std::size_t n;
while(ifs >> n) {
++counter;
std::vector<Scene_polylines_item::Point_3> new_polyline;
polylines.push_back(new_polyline);
std::vector<Scene_polylines_item::Point_3>&polyline = polylines.back();
polyline.reserve(n);
while(n--){
Scene_polylines_item::Point_3 p;
ifs >> p;
polyline.push_back(p);
if(!ifs.good())
{
ok = false;
return QList<Scene_item*>();
}
}
std::string line_remainder;
std::getline(ifs, line_remainder);
QString metadata(line_remainder.c_str());
if(!metadata.isEmpty() && metadata[0].isSpace()) {
metadata.remove(0, 1);
}
polylines_metadata << metadata;
if(!metadata.isEmpty()) {
std::cerr << " (metadata: \"" << qPrintable(metadata) << "\")\n";
} else {
}
if(ifs.bad() || ifs.fail())
{
ok = false;
return QList<Scene_item*>();
}
}
if(counter == 0)
{
ok = false;
return QList<Scene_item*>();
}
Scene_polylines_item* item = new Scene_polylines_item;
item->polylines = polylines;
item->setName(fileinfo.completeBaseName());
item->setColor(Qt::black);
item->setProperty("polylines metadata", polylines_metadata);
std::cerr << "Number of polylines in item: " << item->polylines.size() << std::endl;
item->invalidateOpenGLBuffers();
ok = true;
if(add_to_scene)
CGAL::Three::Three::scene()->addItem(item);
return QList<Scene_item*>()<<item;
}
bool Polyhedron_demo_polylines_io_plugin::canSave(const CGAL::Three::Scene_item* item)
{
return qobject_cast<const Scene_polylines_item*>(item) != 0;
}
bool Polyhedron_demo_polylines_io_plugin::
save(QFileInfo fileinfo,QList<CGAL::Three::Scene_item*>& items)
{
Scene_item* item = items.front();
const Scene_polylines_item* poly_item =
qobject_cast<const Scene_polylines_item*>(item);
if(!poly_item)
return false;
std::ofstream out(fileinfo.filePath().toUtf8());
out.precision (std::numeric_limits<double>::digits10 + 2);
if(!out) {
std::cerr << "Error! Cannot open file " << (const char*)fileinfo.filePath().toUtf8() << std::endl;
return false;
}
typedef Scene_polylines_item::Polylines_container Polylines_container;
typedef Polylines_container::value_type Polyline;
typedef Polyline::value_type Point_3;
QStringList metadata = item->property("polylines metadata").toStringList();
for(const Polyline& polyline : poly_item->polylines) {
out << polyline.size();
for(const Point_3& p : polyline) {
out << " " << p.x() << " " << p.y() << " " << p.z();
}
if(!metadata.isEmpty()) {
out << " " << qPrintable(metadata.front());
metadata.pop_front();
}
out << std::endl;
}
bool res = (bool) out;
if(res)
items.pop_front();
return res;
}
void Polyhedron_demo_polylines_io_plugin::split()
{
Scene_polylines_item* item = qobject_cast<Scene_polylines_item*>(scene->item(scene->mainSelectionIndex()));
Scene_group_item* group = new Scene_group_item("Split Polylines");
scene->addItem(group);
group->setColor(item->color());
int i=0;
for(Scene_polylines_item::Polyline polyline: item->polylines)
{
Scene_polylines_item::Polylines_container container;
container.push_back(polyline);
Scene_polylines_item *new_polyline = new Scene_polylines_item();
new_polyline->polylines = container;
new_polyline->setColor(item->color());
new_polyline->setName(QString("Split %1 #%2").arg(item->name()).arg(i++));
scene->addItem(new_polyline);
scene->changeGroup(new_polyline, group);
}
}
template <typename P,
typename PolylineInputIterator>
void
polylines_to_split(std::vector<std::vector<P> >& polylines,
PolylineInputIterator existing_polylines_begin,
PolylineInputIterator existing_polylines_end)
{
typedef P Point_3;
typedef typename CGAL::Kernel_traits<P>::Kernel K;
using CGAL::internal::polylines_to_protect_namespace::Vertex_info;
typedef boost::adjacency_list<boost::setS, boost::vecS, boost::undirectedS,
Vertex_info<Point_3> > Graph;
typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename std::iterator_traits<PolylineInputIterator>::value_type Polyline;
Graph graph;
typedef CGAL::Mesh_3::internal::Returns_midpoint<K, int> Midpoint_fct;
CGAL::Mesh_3::internal::Graph_manipulations<Graph,
Point_3,
int,
Midpoint_fct> g_manip(graph);
for (PolylineInputIterator poly_it = existing_polylines_begin;
poly_it != existing_polylines_end; ++poly_it)
{
Polyline polyline = *poly_it;
if (polyline.size() < 2)
continue;
typename Polyline::iterator pit = polyline.begin();
while (std::next(pit) != polyline.end())
{
vertex_descriptor v = g_manip.get_vertex(*pit, false);
vertex_descriptor w = g_manip.get_vertex(*std::next(pit), false);
g_manip.try_add_edge(v, w);
++pit;
}
}
CGAL::Mesh_3::Polyline_visitor<Point_3, Graph> visitor(polylines, graph);
const Graph& const_graph = graph;
typedef typename CGAL::Kernel_traits<P>::Kernel K;
CGAL::split_graph_into_polylines(const_graph, visitor);
}
void Polyhedron_demo_polylines_io_plugin::split_graph()
{
Scene_item* main_item = scene->item(scene->mainSelectionIndex());
Scene_polylines_item* polylines_item =
qobject_cast<Scene_polylines_item*>(main_item);
if(polylines_item == nullptr) return;
std::vector<Scene_polylines_item::Polylines_container::value_type> new_polylines;
polylines_to_split(new_polylines, polylines_item->polylines.begin(), polylines_item->polylines.end());
Scene_polylines_item* new_item = new Scene_polylines_item;
new_item->polylines =
Scene_polylines_item::Polylines_container{new_polylines.begin(), new_polylines.end()};
new_item->setName(tr("%1 (split)").arg(polylines_item->name()));
scene->addItem(new_item);
}
void Polyhedron_demo_polylines_io_plugin::simplify()
{
Scene_polylines_item* item = qobject_cast<Scene_polylines_item*>(scene->item(scene->mainSelectionIndex()));
bool ok;
double err = QInputDialog::getDouble(mw, "Squared Frechet Distance", "Enter the squared approximation error:", pow(0.01*item->bboxDiagonal(),2),0,999,8,&ok);
if(!ok)
return;
for(Scene_polylines_item::Polylines_container::iterator
it = item->polylines.begin();
it!= item->polylines.end();
++it)
{
Scene_polylines_item::Polyline out_range;
CGAL::Polygon_mesh_processing::experimental::simplify_polyline(*it,
out_range,
err);
it->clear();
it->insert(it->begin(), out_range.begin(), out_range.end());
}
item->invalidateOpenGLBuffers();
item->redraw();
}
void Polyhedron_demo_polylines_io_plugin::join()
{
std::vector<Scene_polylines_item*> items;
items.resize(scene->selectionIndices().size());
for(int i = 0; i < scene->selectionIndices().size(); ++i)
items[i] = qobject_cast<Scene_polylines_item*>(scene->item(scene->selectionIndices().at(i)));
Scene_polylines_item* new_polyline= new Scene_polylines_item();
Scene_polylines_item::Polylines_container container;
for(Scene_polylines_item* item: items)
{
for(Scene_polylines_item::Polylines_container::iterator
it = item->polylines.begin();
it!= item->polylines.end();
++it)
{
container.push_back(*it);
}
}
new_polyline->polylines = container;
new_polyline->setColor(QColor(Qt::black));
new_polyline->setName(QString("Joined from %1 items").arg(items.size()));
scene->addItem(new_polyline);
}
#include "Polylines_io_plugin.moc"