mirror of https://github.com/CGAL/cgal
1143 lines
38 KiB
C++
1143 lines
38 KiB
C++
#include <QApplication>
|
|
#include <QAction>
|
|
#include <QMainWindow>
|
|
#include <QStringList>
|
|
#ifdef USE_SURFACE_MESH
|
|
#include "Scene_surface_mesh_item.h"
|
|
#include "Scene_textured_surface_mesh_item.h"
|
|
#include "Scene_polyhedron_selection_item.h"
|
|
#include "SMesh_type.h"
|
|
#else
|
|
#include "Scene_polyhedron_item.h"
|
|
#include "Scene_textured_polyhedron_item.h"
|
|
#include "Scene_polyhedron_selection_item.h"
|
|
#include "Textured_polyhedron_type.h"
|
|
#include "Polyhedron_type.h"
|
|
#include <CGAL/Polyhedron_3.h>
|
|
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
|
|
#include <CGAL/Textured_polyhedron_builder.h>
|
|
#include <CGAL/Three/Polyhedron_demo_plugin_helper.h>
|
|
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
|
|
#include <CGAL/Polyhedron_items_with_id_3.h>
|
|
#endif
|
|
#include <CGAL/Three/Polyhedron_demo_plugin_helper.h>
|
|
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
|
|
#include "Scene.h"
|
|
#include <QTime>
|
|
#include <QGraphicsScene>
|
|
#include <QGraphicsItem>
|
|
#include <QPen>
|
|
#include <QDockWidget>
|
|
#include <Messages_interface.h>
|
|
#include <CGAL/Polygon_mesh_processing/border.h>
|
|
#include <CGAL/Polygon_mesh_processing/measure.h>
|
|
#include <CGAL/property_map.h>
|
|
|
|
|
|
#include <CGAL/boost/graph/Seam_mesh.h>
|
|
#include <CGAL/boost/graph/graph_traits_Seam_mesh.h>
|
|
|
|
#include <CGAL/Surface_mesh_parameterization/ARAP_parameterizer_3.h>
|
|
#include <CGAL/Surface_mesh_parameterization/Barycentric_mapping_parameterizer_3.h>
|
|
#include <CGAL/Surface_mesh_parameterization/Discrete_authalic_parameterizer_3.h>
|
|
#include <CGAL/Surface_mesh_parameterization/Discrete_conformal_map_parameterizer_3.h>
|
|
#include <CGAL/Surface_mesh_parameterization/Error_code.h>
|
|
#include <CGAL/Surface_mesh_parameterization/LSCM_parameterizer_3.h>
|
|
#include <CGAL/Surface_mesh_parameterization/Two_vertices_parameterizer_3.h>
|
|
#include <CGAL/Surface_mesh_parameterization/internal/orbifold_cone_helper.h>
|
|
#include <CGAL/Surface_mesh_parameterization/Orbifold_Tutte_parameterizer_3.h>
|
|
#include <CGAL/Surface_mesh_parameterization/parameterize.h>
|
|
|
|
|
|
#include <boost/foreach.hpp>
|
|
#include <boost/unordered_map.hpp>
|
|
#include <boost/unordered_set.hpp>
|
|
#include <boost/container/flat_map.hpp>
|
|
|
|
#include <algorithm>
|
|
#include <iostream>
|
|
#include <iterator>
|
|
#include <vector>
|
|
|
|
|
|
#include <CGAL/boost/graph/properties.h>
|
|
#include <CGAL/Qt/GraphicsViewNavigation.h>
|
|
|
|
#include "ui_Parameterization_widget.h"
|
|
#include "ui_ARAP_dialog.h"
|
|
#include "ui_OTE_dialog.h"
|
|
|
|
#ifdef USE_SURFACE_MESH
|
|
typedef Scene_surface_mesh_item Scene_facegraph_item;
|
|
typedef Scene_textured_surface_mesh_item Scene_textured_facegraph_item;
|
|
typedef SMesh Textured_face_graph;
|
|
typedef SMesh Base_face_graph;
|
|
typedef SMesh Face_graph;
|
|
typedef EPICK Traits;
|
|
|
|
#else
|
|
typedef Scene_polyhedron_item Scene_facegraph_item;
|
|
typedef Scene_textured_polyhedron_item Scene_textured_facegraph_item;
|
|
typedef Textured_polyhedron Textured_face_graph;
|
|
typedef Textured_face_graph::Base Base_face_graph;
|
|
typedef Polyhedron Face_graph;
|
|
typedef Kernel Traits;
|
|
|
|
#endif
|
|
|
|
namespace SMP = CGAL::Surface_mesh_parameterization;
|
|
|
|
typedef boost::unordered_set<boost::graph_traits<Base_face_graph>::face_descriptor> Component;
|
|
typedef std::vector<Component> Components;
|
|
|
|
struct Is_selected_property_map{
|
|
typedef boost::graph_traits<Base_face_graph>::edge_descriptor edge_descriptor;
|
|
typedef boost::property_map<Base_face_graph, boost::halfedge_index_t>::type HIndexMap;
|
|
std::vector<bool>* is_selected_ptr;
|
|
Base_face_graph* graph;
|
|
HIndexMap idmap;
|
|
Is_selected_property_map()
|
|
: is_selected_ptr(NULL), graph(NULL) {}
|
|
Is_selected_property_map(std::vector<bool>& is_selected,
|
|
Base_face_graph* graph)
|
|
: is_selected_ptr( &is_selected), graph(graph)
|
|
{
|
|
idmap = get(boost::halfedge_index, *graph);
|
|
}
|
|
|
|
std::size_t id(edge_descriptor ed) { return get(idmap, halfedge(ed, *graph))/2; }
|
|
|
|
friend bool get(Is_selected_property_map map, edge_descriptor ed)
|
|
{
|
|
CGAL_assertion(map.is_selected_ptr!=NULL);
|
|
return (*map.is_selected_ptr)[map.id(ed)];
|
|
}
|
|
|
|
friend void put(Is_selected_property_map map, edge_descriptor ed, bool b)
|
|
{
|
|
CGAL_assertion(map.is_selected_ptr!=NULL);
|
|
(*map.is_selected_ptr)[map.id(ed)]=b;
|
|
}
|
|
};
|
|
|
|
class Navigation : public CGAL::Qt::GraphicsViewNavigation
|
|
{
|
|
public:
|
|
Navigation()
|
|
:CGAL::Qt::GraphicsViewNavigation(),
|
|
prev_pos(QPoint(0,0))
|
|
{ }
|
|
|
|
protected:
|
|
bool eventFilter(QObject *obj, QEvent *ev)
|
|
{
|
|
QGraphicsView* v = qobject_cast<QGraphicsView*>(obj);
|
|
if(v == NULL) {
|
|
QWidget* viewport = qobject_cast<QWidget*>(obj);
|
|
if(viewport == NULL) {
|
|
return false;
|
|
}
|
|
v = qobject_cast<QGraphicsView*>(viewport->parent());
|
|
if(v == NULL) {
|
|
return false;
|
|
}
|
|
}
|
|
switch(ev->type())
|
|
{
|
|
case QEvent::MouseMove: {
|
|
QMouseEvent* me = static_cast<QMouseEvent*>(ev);
|
|
if(is_dragging)
|
|
{
|
|
qreal dir[2] = {v->mapToScene(me->pos()).x() - prev_pos.x(),
|
|
v->mapToScene(me->pos()).y() - prev_pos.y()};
|
|
|
|
v->translate(dir[0],dir[1]);
|
|
v->update();
|
|
}
|
|
prev_pos = v->mapToScene(me->pos());
|
|
break;
|
|
}
|
|
|
|
case QEvent::MouseButtonPress: {
|
|
is_dragging = true;
|
|
break;
|
|
}
|
|
case QEvent::MouseButtonRelease: {
|
|
is_dragging = false;
|
|
break;
|
|
}
|
|
case QEvent::Wheel: {
|
|
QWheelEvent* event = static_cast<QWheelEvent*>(ev);
|
|
QPointF old_pos = v->mapToScene(event->pos());
|
|
if(event->delta() <0)
|
|
v->scale(1.2, 1.2);
|
|
else
|
|
v->scale(0.8, 0.8);
|
|
QPointF new_pos = v->mapToScene(event->pos());
|
|
QPointF delta = new_pos - old_pos;
|
|
v->translate(delta.x(), delta.y());
|
|
v->update();
|
|
break;
|
|
}
|
|
|
|
case QEvent::MouseButtonDblClick: {
|
|
v->fitInView(v->scene()->itemsBoundingRect(), Qt::KeepAspectRatio);
|
|
break;
|
|
}
|
|
default:
|
|
CGAL::Qt::GraphicsViewNavigation::eventFilter(obj, ev);
|
|
}
|
|
return false;
|
|
}
|
|
private:
|
|
bool is_dragging;
|
|
QPointF prev_pos;
|
|
};
|
|
|
|
namespace SMP = CGAL::Surface_mesh_parameterization;
|
|
|
|
typedef Traits::FT FT;
|
|
typedef boost::graph_traits<Face_graph>::vertex_descriptor P_vertex_descriptor;
|
|
typedef Traits::Point_2 Point_2;
|
|
typedef boost::graph_traits<Face_graph>::edge_descriptor P_edge_descriptor;
|
|
typedef boost::graph_traits<Face_graph>::halfedge_descriptor P_halfedge_descriptor;
|
|
|
|
// Textured polyhedron
|
|
typedef boost::graph_traits<Base_face_graph>::
|
|
edge_descriptor T_edge_descriptor;
|
|
typedef boost::graph_traits<Base_face_graph>::
|
|
halfedge_descriptor T_halfedge_descriptor;
|
|
typedef boost::graph_traits<Base_face_graph>::
|
|
vertex_descriptor T_vertex_descriptor;
|
|
|
|
// Seam
|
|
typedef CGAL::Unique_hash_map<T_halfedge_descriptor,Point_2> UV_uhm;
|
|
typedef CGAL::Unique_hash_map<T_edge_descriptor,bool> Seam_edge_uhm;
|
|
typedef CGAL::Unique_hash_map<T_vertex_descriptor,bool> Seam_vertex_uhm;
|
|
|
|
typedef boost::associative_property_map<UV_uhm> UV_pmap;
|
|
typedef boost::associative_property_map<Seam_edge_uhm> Seam_edge_pmap;
|
|
typedef boost::associative_property_map<Seam_vertex_uhm> Seam_vertex_pmap;
|
|
|
|
typedef CGAL::Seam_mesh<Base_face_graph,
|
|
Seam_edge_pmap, Seam_vertex_pmap> Seam_mesh;
|
|
|
|
typedef boost::graph_traits<Seam_mesh>::vertex_descriptor s_vertex_descriptor;
|
|
typedef boost::graph_traits<Seam_mesh>::halfedge_descriptor s_halfedge_descriptor;
|
|
typedef boost::graph_traits<Seam_mesh>::face_descriptor s_face_descriptor;
|
|
|
|
typedef boost::graph_traits<Seam_mesh>::edges_size_type s_edges_size_type;
|
|
|
|
typedef boost::unordered_set<boost::graph_traits<Base_face_graph>::
|
|
face_descriptor> Component;
|
|
typedef std::vector<Component> Components;
|
|
|
|
typedef boost::unordered_set<s_face_descriptor> SComponent;
|
|
typedef std::vector<SComponent> SComponents;
|
|
|
|
class UVItem : public QGraphicsItem
|
|
{
|
|
public :
|
|
UVItem(Components* components,
|
|
Base_face_graph* graph,
|
|
std::vector<std::vector<float> >uv_borders,
|
|
QRectF brect)
|
|
:
|
|
QGraphicsItem(),
|
|
bounding_rect(brect),
|
|
components(components),
|
|
graph(graph),
|
|
m_borders(uv_borders),
|
|
m_concatenated_borders(),
|
|
m_current_component(0)
|
|
{
|
|
std::size_t total_border_size = 0;
|
|
for(std::size_t i=0; i<m_borders.size(); ++i)
|
|
total_border_size += m_borders[i].size();
|
|
|
|
m_concatenated_borders.resize(total_border_size);
|
|
for(std::size_t i=0; i<m_borders.size(); ++i)
|
|
{
|
|
const std::vector<float>& ith_border = m_borders[i];
|
|
m_concatenated_borders.insert(m_concatenated_borders.end(),
|
|
ith_border.begin(), ith_border.end());
|
|
}
|
|
}
|
|
|
|
~UVItem()
|
|
{
|
|
delete components;
|
|
}
|
|
|
|
const std::vector<std::vector<float> >& borders() const { return m_borders; }
|
|
const std::vector<float>& concatenated_borders() const { return m_concatenated_borders; }
|
|
|
|
QRectF boundingRect() const
|
|
{
|
|
return bounding_rect;
|
|
}
|
|
|
|
QString item_name()const{ return texMesh_name; }
|
|
void set_item_name(QString s){ texMesh_name = s;}
|
|
|
|
void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
|
|
{
|
|
QPen pen;
|
|
QBrush brush;
|
|
brush.setColor(QColor(100, 100, 255));
|
|
brush.setStyle(Qt::SolidPattern);
|
|
pen.setColor(Qt::black);
|
|
pen.setWidth(0);
|
|
painter->setPen(pen);
|
|
painter->setBrush(brush);
|
|
#ifdef USE_SURFACE_MESH
|
|
SMesh::Property_map<halfedge_descriptor,std::pair<float, float> > uv;
|
|
uv = graph->add_property_map<halfedge_descriptor,std::pair<float, float> >("h:uv",std::make_pair(0.0f,0.0f)).first;
|
|
#endif
|
|
for( Component::iterator
|
|
fi = components->at(m_current_component).begin();
|
|
fi != components->at(m_current_component).end();
|
|
++fi)
|
|
{
|
|
boost::graph_traits<Base_face_graph>::face_descriptor f(*fi);
|
|
#ifdef USE_SURFACE_MESH
|
|
QPointF points[3];
|
|
boost::graph_traits<Base_face_graph>::halfedge_descriptor h = halfedge(f, *graph);;
|
|
points[0] = QPointF(get(uv, h).first, get(uv, h).second);
|
|
h = next(halfedge(f, *graph), *graph);
|
|
points[1] = QPointF(get(uv, h).first, get(uv, h).second);
|
|
h = next(next(halfedge(f, *graph), *graph), *graph);
|
|
points[2] = QPointF(get(uv, h).first, get(uv, h).second);
|
|
#else
|
|
QPointF points[3];
|
|
points[0] = QPointF(halfedge(f, *graph)->u(), f->halfedge()->v());
|
|
points[1] = QPointF(halfedge(f, *graph)->next()->u(), f->halfedge()->next()->v());
|
|
points[2] = QPointF(halfedge(f, *graph)->next()->next()->u(), f->halfedge()->next()->next()->v());
|
|
#endif
|
|
|
|
painter->drawPolygon(points,3);
|
|
}
|
|
}
|
|
|
|
int number_of_components()const{return static_cast<int>(components->size());}
|
|
int current_component()const{return m_current_component;}
|
|
void set_current_component(int n){m_current_component = n;}
|
|
|
|
private:
|
|
QString texMesh_name;
|
|
QRectF bounding_rect;
|
|
Components* components;
|
|
Base_face_graph* graph;
|
|
std::vector<std::vector<float> > m_borders;
|
|
std::vector<float> m_concatenated_borders;
|
|
int m_current_component;
|
|
};
|
|
|
|
using namespace CGAL::Three;
|
|
|
|
class Polyhedron_demo_parameterization_plugin :
|
|
public QObject,
|
|
public Polyhedron_demo_plugin_helper
|
|
{
|
|
Q_OBJECT
|
|
Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface)
|
|
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0")
|
|
|
|
public:
|
|
// used by Polyhedron_demo_plugin_helper
|
|
QList<QAction*> actions() const
|
|
{
|
|
return _actions;
|
|
}
|
|
|
|
void init(QMainWindow* mainWindow,
|
|
Scene_interface* scene_interface,
|
|
Messages_interface* msg)
|
|
{
|
|
mw = mainWindow;
|
|
scene = scene_interface;
|
|
messages = msg;
|
|
Scene* true_scene = static_cast<Scene*>(scene);
|
|
connect(true_scene, SIGNAL(itemAboutToBeDestroyed(CGAL::Three::Scene_item*)),
|
|
this, SLOT(destroyPolyline(CGAL::Three::Scene_item*)));
|
|
QAction* actionMVC = new QAction("Mean Value Coordinates", mw);
|
|
QAction* actionDCP = new QAction ("Discrete Conformal Map", mw);
|
|
QAction* actionLSC = new QAction("Least Square Conformal Map", mw);
|
|
QAction* actionDAP = new QAction("Discrete Authalic", mw);
|
|
QAction* actionARAP = new QAction("As Rigid As Possible", mw);
|
|
QAction* actionOTE = new QAction("Orbifold Tutte Embedding", mw);
|
|
QAction* actionBTP = new QAction("Tutte Barycentric", mw);
|
|
actionMVC->setObjectName("actionMVC");
|
|
actionDCP->setObjectName("actionDCP");
|
|
actionLSC->setObjectName("actionLSC");
|
|
actionDAP->setObjectName("actionDAP");
|
|
actionARAP->setObjectName("actionARAP");
|
|
actionOTE->setObjectName("actionOTE");
|
|
actionBTP->setObjectName("actionBTP");
|
|
|
|
_actions << actionARAP
|
|
<< actionBTP
|
|
<< actionDAP
|
|
<< actionDCP
|
|
<< actionLSC
|
|
<< actionMVC
|
|
<< actionOTE;
|
|
autoConnectActions();
|
|
Q_FOREACH(QAction *action, _actions)
|
|
action->setProperty("subMenuName",
|
|
"Triangulated Surface Mesh Parameterization");
|
|
dock_widget = new QDockWidget("UVMapping", mw);
|
|
ui_widget.setupUi(dock_widget);
|
|
graphics_scene = new QGraphicsScene(dock_widget);
|
|
ui_widget.graphicsView->setScene(graphics_scene);
|
|
ui_widget.graphicsView->setRenderHints(QPainter::Antialiasing);
|
|
navigation = new Navigation();
|
|
ui_widget.graphicsView->installEventFilter(navigation);
|
|
ui_widget.graphicsView->viewport()->installEventFilter(navigation);
|
|
ui_widget.component_numberLabel->setText("Component : 1");
|
|
connect(ui_widget.prevButton, &QPushButton::clicked, this, &Polyhedron_demo_parameterization_plugin::on_prevButton_pressed);
|
|
connect(ui_widget.nextButton, &QPushButton::clicked, this, &Polyhedron_demo_parameterization_plugin::on_nextButton_pressed);
|
|
addDockWidget(dock_widget);
|
|
dock_widget->setVisible(false);
|
|
current_uv_item = NULL;
|
|
}
|
|
|
|
bool applicable(QAction*) const
|
|
{
|
|
if (scene->selectionIndices().size() == 1)
|
|
{
|
|
return qobject_cast<Scene_facegraph_item*>(scene->item(scene->mainSelectionIndex()))
|
|
|| qobject_cast<Scene_polyhedron_selection_item*>(scene->item(scene->mainSelectionIndex()));
|
|
}
|
|
|
|
Q_FOREACH(CGAL::Three::Scene_interface::Item_id id, scene->selectionIndices())
|
|
{
|
|
//if one facegraph is found in the selection, it's fine
|
|
if (qobject_cast<Scene_facegraph_item*>(scene->item(id)))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void closure()
|
|
{
|
|
dock_widget->hide();
|
|
}
|
|
|
|
public Q_SLOTS:
|
|
void on_actionMVC_triggered();
|
|
void on_actionDCP_triggered();
|
|
void on_actionLSC_triggered();
|
|
void on_actionDAP_triggered();
|
|
void on_actionARAP_triggered();
|
|
void on_actionOTE_triggered();
|
|
void on_actionBTP_triggered();
|
|
void on_prevButton_pressed();
|
|
void on_nextButton_pressed();
|
|
|
|
void replacePolyline()
|
|
{
|
|
if(current_uv_item)
|
|
qobject_cast<Scene_textured_facegraph_item*>(projections.key(current_uv_item))->add_border_edges(std::vector<float>(0));
|
|
|
|
int id = scene->mainSelectionIndex();
|
|
|
|
Q_FOREACH(UVItem* pl, projections)
|
|
{
|
|
if(pl==NULL || pl != projections[scene->item(id)])
|
|
continue;
|
|
current_uv_item = pl;
|
|
break;
|
|
}
|
|
|
|
if(!current_uv_item)
|
|
{
|
|
dock_widget->setWindowTitle(tr("UVMapping"));
|
|
ui_widget.component_numberLabel->setText(QString("Component :"));
|
|
}
|
|
else
|
|
{
|
|
if(!graphics_scene->items().empty())
|
|
graphics_scene->removeItem(graphics_scene->items().first());
|
|
|
|
graphics_scene->addItem(current_uv_item);
|
|
ui_widget.graphicsView->fitInView(current_uv_item->boundingRect(), Qt::KeepAspectRatio);
|
|
ui_widget.component_numberLabel->setText(QString("Component : %1/%2").arg(current_uv_item->current_component()+1).arg(current_uv_item->number_of_components()));
|
|
dock_widget->setWindowTitle(tr("UVMapping for %1").arg(current_uv_item->item_name()));
|
|
qobject_cast<Scene_textured_facegraph_item*>(projections.key(current_uv_item))->add_border_edges(current_uv_item->concatenated_borders());
|
|
}
|
|
}
|
|
|
|
void destroyPolyline(CGAL::Three::Scene_item* item)
|
|
{
|
|
Q_FOREACH(UVItem* pli, projections)
|
|
{
|
|
if(projections.key(pli) != item)
|
|
continue;
|
|
graphics_scene->removeItem(pli);
|
|
delete pli;
|
|
projections.remove(item);
|
|
break;
|
|
}
|
|
|
|
if(projections.empty() || projections.first() == NULL)
|
|
{
|
|
current_uv_item = NULL;
|
|
dock_widget->setWindowTitle(tr("UVMapping"));
|
|
ui_widget.component_numberLabel->setText(QString("Component :"));
|
|
}
|
|
else
|
|
current_uv_item = projections.first();
|
|
}
|
|
|
|
protected:
|
|
enum Parameterization_method { PARAM_MVC, PARAM_DCP, PARAM_LSC,
|
|
PARAM_DAP, PARAM_ARAP, PARAM_OTE, PARAM_BTP};
|
|
void parameterize(Parameterization_method method);
|
|
|
|
private:
|
|
Messages_interface *messages;
|
|
QList<QAction*> _actions;
|
|
QDockWidget* dock_widget;
|
|
Ui::Parameterization ui_widget;
|
|
QGraphicsScene *graphics_scene;
|
|
Navigation* navigation;
|
|
QMap<Scene_item*, UVItem*> projections;
|
|
UVItem* current_uv_item;
|
|
}; // end Polyhedron_demo_parameterization_plugin
|
|
|
|
void Polyhedron_demo_parameterization_plugin::on_prevButton_pressed()
|
|
{
|
|
int id = scene->mainSelectionIndex();
|
|
Q_FOREACH(UVItem* pl, projections)
|
|
{
|
|
if(pl==NULL
|
|
|| pl != projections[scene->item(id)])
|
|
continue;
|
|
|
|
current_uv_item = pl;
|
|
break;
|
|
}
|
|
if(current_uv_item == NULL)
|
|
return;
|
|
current_uv_item->set_current_component((std::max)(0,current_uv_item->current_component()-1));
|
|
replacePolyline();
|
|
}
|
|
|
|
void Polyhedron_demo_parameterization_plugin::on_nextButton_pressed()
|
|
{
|
|
int id = scene->mainSelectionIndex();
|
|
Q_FOREACH(UVItem* pl, projections)
|
|
{
|
|
if(pl==NULL
|
|
|| pl != projections[scene->item(id)])
|
|
continue;
|
|
|
|
current_uv_item = pl;
|
|
break;
|
|
}
|
|
if(current_uv_item == NULL)
|
|
return;
|
|
current_uv_item->set_current_component((std::min)(current_uv_item->number_of_components()-1,current_uv_item->current_component()+1));
|
|
ui_widget.component_numberLabel->setText(QString("Component : %1/%2").arg(current_uv_item->current_component()+1).arg(current_uv_item->number_of_components()));
|
|
replacePolyline();
|
|
}
|
|
|
|
void Polyhedron_demo_parameterization_plugin::parameterize(const Parameterization_method method)
|
|
{
|
|
// get active polyhedron
|
|
Scene_facegraph_item* poly_item = NULL;
|
|
CGAL::Three::Scene_interface::Item_id index = scene->mainSelectionIndex();
|
|
Q_FOREACH(CGAL::Three::Scene_interface::Item_id id, scene->selectionIndices())
|
|
{
|
|
poly_item = qobject_cast<Scene_facegraph_item*>(scene->item(id));
|
|
if(!poly_item)
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
index = id;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!poly_item)
|
|
{
|
|
messages->error("Selected item is not of the right type.");
|
|
return;
|
|
}
|
|
|
|
Face_graph* pMesh = poly_item->face_graph();
|
|
if(!pMesh)
|
|
{
|
|
messages->error("Selected item has no valid polyhedron.");
|
|
return;
|
|
}
|
|
#ifndef USE_SURFACE_MESH
|
|
pMesh->normalize_border();
|
|
#endif
|
|
Scene_polyhedron_selection_item* sel_item = NULL;
|
|
bool is_seamed = false;
|
|
Q_FOREACH(CGAL::Three::Scene_interface::Item_id id, scene->selectionIndices())
|
|
{
|
|
sel_item = qobject_cast<Scene_polyhedron_selection_item*>(scene->item(id));
|
|
if(!sel_item)
|
|
continue;
|
|
if(sel_item->selected_edges.empty())
|
|
continue;
|
|
if(method == PARAM_OTE && sel_item->selected_vertices.empty())
|
|
continue;
|
|
is_seamed = true;
|
|
}
|
|
|
|
if(method == PARAM_OTE &&
|
|
(sel_item == NULL || sel_item->selected_vertices.empty())) {
|
|
std::cerr << "No selection or no cones selected; Aborting." << std::endl;
|
|
return;
|
|
}
|
|
|
|
// Two property maps to store the seam edges and vertices
|
|
Seam_edge_uhm seam_edge_uhm(false);
|
|
Seam_edge_pmap seam_edge_pm(seam_edge_uhm);
|
|
|
|
Seam_vertex_uhm seam_vertex_uhm(false);
|
|
Seam_vertex_pmap seam_vertex_pm(seam_vertex_uhm);
|
|
|
|
if(!is_seamed && is_closed(*pMesh))
|
|
{
|
|
messages->error("The selected mesh has no (real or virtual) border.");
|
|
return;
|
|
}
|
|
|
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
|
|
|
///////////////////////////////////
|
|
////////// PARAMETERIZE ///////////
|
|
///////////////////////////////////
|
|
|
|
QTime time;
|
|
time.start();
|
|
// add textured polyhedon to the scene
|
|
#ifndef USE_SURFACE_MESH
|
|
Textured_polyhedron *tpMesh = new Textured_polyhedron();
|
|
Textured_polyhedron_builder<Polyhedron,Textured_polyhedron,Kernel> builder;
|
|
builder.run(*pMesh,*tpMesh);
|
|
tpMesh->compute_normals();
|
|
tpMesh->normalize_border();
|
|
Base_face_graph tMesh = static_cast<Base_face_graph&>(*tpMesh);
|
|
|
|
CGAL::set_halfedgeds_items_id(tMesh);
|
|
std::vector<bool> mark(tpMesh->size_of_halfedges()/2,false);
|
|
std::vector<T_edge_descriptor> seam_edges;
|
|
if(is_seamed)
|
|
{
|
|
//create a textured_polyhedron edges selection from the ids of the corresponding vertices
|
|
BOOST_FOREACH(P_edge_descriptor ed, sel_item->selected_edges)
|
|
{
|
|
Polyhedron::Vertex_handle a(source(ed, *pMesh)), b(target(ed, *pMesh));
|
|
|
|
for(Textured_polyhedron::Edge_iterator it =
|
|
tMesh.edges_begin(); it != tMesh.edges_end();
|
|
++it)
|
|
{
|
|
Textured_polyhedron::Vertex_handle ta(source(it, tMesh)), tb(target(it, tMesh));
|
|
if((ta->id() == a->id() && tb->id() == b->id())
|
|
||
|
|
(ta->id() == b->id() && tb->id() == a->id()))
|
|
{
|
|
T_edge_descriptor ted(it);
|
|
seam_edges.push_back(ted);
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
qDebug() << sel_item->selected_edges.size() << ", " << seam_edges.size();
|
|
//fill seam mesh pmaps
|
|
BOOST_FOREACH(T_edge_descriptor ed, seam_edges)
|
|
{
|
|
T_halfedge_descriptor hd = halfedge(ed, tMesh);
|
|
T_vertex_descriptor svd(source(hd, tMesh)), tvd(target(hd, tMesh));
|
|
if(!is_border(ed, tMesh))
|
|
{
|
|
put(seam_edge_pm, ed, true);
|
|
put(seam_vertex_pm, svd, true);
|
|
put(seam_vertex_pm, tvd, true);
|
|
mark[hd->id()/2] = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// map the cones from the selection plugin to the textured polyhedron
|
|
boost::unordered_set<T_vertex_descriptor> unordered_cones;
|
|
if(method == PARAM_OTE) {
|
|
BOOST_FOREACH(P_vertex_descriptor vd, sel_item->selected_vertices) {
|
|
Polyhedron::Vertex_handle pvd(vd);
|
|
Textured_polyhedron::Vertex_iterator it = tMesh.vertices_begin(),
|
|
end = tMesh.vertices_end();
|
|
for(; it!=end; ++it) {
|
|
Textured_polyhedron::Vertex_handle tvd(it);
|
|
if(it->id() == pvd->id()) {
|
|
unordered_cones.insert(tvd);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
// \todo for surface_mesh
|
|
Base_face_graph tMesh = *pMesh;
|
|
std::vector<bool> mark(num_halfedges(tMesh)/2,false);
|
|
std::vector<T_edge_descriptor> seam_edges;
|
|
typedef boost::property_map<Base_face_graph, boost::vertex_index_t>::type VIDMap;
|
|
VIDMap vidmap = get(boost::vertex_index, tMesh);
|
|
if(is_seamed)
|
|
{
|
|
//create a textured_polyhedron edges selection from the ids of the corresponding vertices
|
|
typedef boost::property_map<Base_face_graph, boost::halfedge_index_t>::type HIDMap;
|
|
HIDMap hidmap = get(boost::halfedge_index, tMesh);
|
|
BOOST_FOREACH(P_edge_descriptor ed, sel_item->selected_edges)
|
|
{
|
|
boost::graph_traits<Face_graph>::vertex_descriptor a(source(ed, *pMesh)), b(target(ed, *pMesh));
|
|
|
|
for(boost::graph_traits<Textured_face_graph>::edge_iterator it =
|
|
edges(tMesh).begin(); it != edges(tMesh).end();
|
|
++it)
|
|
{
|
|
boost::graph_traits<Textured_face_graph>::vertex_descriptor ta(source(*it, tMesh)), tb(target(*it, tMesh));
|
|
|
|
if((get(vidmap, ta) == get(vidmap, a) && get(vidmap,tb) == get(vidmap,b))
|
|
||
|
|
(get(vidmap,ta) == get(vidmap,b) && get(vidmap,tb) == get(vidmap,a)))
|
|
{
|
|
T_edge_descriptor ted(*it);
|
|
seam_edges.push_back(ted);
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
qDebug() << sel_item->selected_edges.size() << ", " << seam_edges.size();
|
|
//fill seam mesh pmaps
|
|
BOOST_FOREACH(T_edge_descriptor ed, seam_edges)
|
|
{
|
|
T_halfedge_descriptor hd = halfedge(ed, tMesh);
|
|
T_vertex_descriptor svd(source(hd, tMesh)), tvd(target(hd, tMesh));
|
|
if(!is_border(ed, tMesh))
|
|
{
|
|
put(seam_edge_pm, ed, true);
|
|
put(seam_vertex_pm, svd, true);
|
|
put(seam_vertex_pm, tvd, true);
|
|
mark[get(hidmap, hd)/2] = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// map the cones from the selection plugin to the textured polyhedron
|
|
boost::unordered_set<T_vertex_descriptor> unordered_cones;
|
|
if(method == PARAM_OTE) {
|
|
BOOST_FOREACH(P_vertex_descriptor vd, sel_item->selected_vertices) {
|
|
boost::graph_traits<Face_graph>::vertex_descriptor pvd(vd);
|
|
boost::graph_traits<Textured_face_graph>::vertex_iterator it = vertices(tMesh).begin(),
|
|
end = vertices(tMesh).end();
|
|
for(; it!=end; ++it) {
|
|
boost::graph_traits<Textured_face_graph>::vertex_descriptor tvd(*it);
|
|
if(get(vidmap, *it) == get(vidmap, pvd)) {
|
|
unordered_cones.insert(tvd);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
Seam_mesh sMesh(tMesh, seam_edge_pm, seam_vertex_pm);
|
|
sMesh.set_seam_edges_number(static_cast<s_edges_size_type>(seam_edges.size()));
|
|
|
|
// The parameterized values
|
|
UV_uhm uv_uhm;
|
|
UV_pmap uv_pm(uv_uhm);
|
|
|
|
QString new_item_name;
|
|
//determine the different connected_components
|
|
boost::container::flat_map<boost::graph_traits<Base_face_graph>::face_descriptor, int> face_component_map;
|
|
boost::associative_property_map< boost::container::flat_map<s_face_descriptor, int> >
|
|
fccmap(face_component_map);
|
|
|
|
Is_selected_property_map edge_pmap(mark, &tMesh);
|
|
|
|
int number_of_components =
|
|
CGAL::Polygon_mesh_processing::connected_components(
|
|
tMesh,
|
|
fccmap,
|
|
CGAL::Polygon_mesh_processing::parameters::edge_is_constrained_map(
|
|
edge_pmap));
|
|
|
|
// Next is the gathering of the border halfedges of the connected component.
|
|
// It is wrong to pass the underlying mesh tMesh: a sphere split in half does
|
|
// not have any border if border_halfedges() is run with tMesh.
|
|
//
|
|
// The proper way would be to completely redesign the plugin to use Seam meshes
|
|
// everywhere. But that's not worth it. Instead, we abuse the fact that faces
|
|
// are the same in tMesh and sMesh.
|
|
|
|
// the SEAM MESH faces of each connected component
|
|
SComponents s_components(number_of_components);
|
|
|
|
for(boost::graph_traits<Base_face_graph>::face_iterator fit = faces(tMesh).begin();
|
|
fit != faces(tMesh).end(); ++fit) {
|
|
s_components.at(fccmap[*fit]).insert(s_face_descriptor(*fit));
|
|
}
|
|
|
|
// once per component
|
|
std::vector<std::vector<float> >uv_borders;
|
|
uv_borders.resize(number_of_components);
|
|
|
|
// to track whether the components are successfully parameterized
|
|
SMP::Error_code status = SMP::OK;
|
|
|
|
for(int current_component=0; current_component<number_of_components; ++current_component)
|
|
{
|
|
std::vector<s_halfedge_descriptor> border;
|
|
PMP::border_halfedges(s_components.at(current_component),
|
|
sMesh, std::back_inserter(border));
|
|
|
|
std::cout << sMesh.number_of_seam_edges() << " seams" << std::endl;
|
|
std::cout << (s_components.at(current_component)).size() << " faces" << std::endl;
|
|
std::cout << border.size() << " border halfedges" << std::endl;
|
|
|
|
// find longest border in the connected component
|
|
s_halfedge_descriptor bhd; // a halfedge on the (possibly virtual) border
|
|
boost::unordered_set<s_halfedge_descriptor> visited;
|
|
FT result_len = 0;
|
|
BOOST_FOREACH(s_halfedge_descriptor hd, border)
|
|
{
|
|
assert(is_border(hd, sMesh));
|
|
|
|
if(visited.find(hd) == visited.end())
|
|
{
|
|
FT len = 0;
|
|
BOOST_FOREACH(s_halfedge_descriptor haf, halfedges_around_face(hd, sMesh))
|
|
{
|
|
len += PMP::edge_length(haf, sMesh);
|
|
visited.insert(haf);
|
|
}
|
|
|
|
if(result_len < len)
|
|
{
|
|
result_len = len;
|
|
bhd = hd;
|
|
}
|
|
}
|
|
}
|
|
CGAL_postcondition(bhd != s_halfedge_descriptor());
|
|
CGAL_postcondition(is_border(bhd, sMesh));
|
|
typedef boost::property_map<Base_face_graph, boost::vertex_point_t>::type VPMap;
|
|
VPMap vpmap =get(boost::vertex_point, tMesh);
|
|
|
|
// collect the border edges for that connected component
|
|
BOOST_FOREACH(s_halfedge_descriptor haf, halfedges_around_face(bhd, sMesh))
|
|
{
|
|
uv_borders[current_component].push_back(get(vpmap, source(haf, tMesh)).x());
|
|
uv_borders[current_component].push_back(get(vpmap, source(haf, tMesh)).y());
|
|
uv_borders[current_component].push_back(get(vpmap, source(haf, tMesh)).z());
|
|
|
|
uv_borders[current_component].push_back(get(vpmap, target(haf, tMesh)).x());
|
|
uv_borders[current_component].push_back(get(vpmap, target(haf, tMesh)).y());
|
|
uv_borders[current_component].push_back(get(vpmap, target(haf, tMesh)).z());
|
|
}
|
|
|
|
switch(method)
|
|
{
|
|
case PARAM_MVC:
|
|
{
|
|
std::cout << "Parameterize (MVC)..." << std::endl;
|
|
new_item_name = tr("%1 (parameterized (MVC))").arg(poly_item->name());
|
|
typedef SMP::Mean_value_coordinates_parameterizer_3<Seam_mesh> Parameterizer;
|
|
status = SMP::parameterize(sMesh, Parameterizer(), bhd, uv_pm);
|
|
break;
|
|
}
|
|
case PARAM_DCP:
|
|
{
|
|
new_item_name = tr("%1 (parameterized (DCP))").arg(poly_item->name());
|
|
std::cout << "Parameterize (DCP)..." << std::endl;
|
|
typedef SMP::Discrete_conformal_map_parameterizer_3<Seam_mesh> Parameterizer;
|
|
status = SMP::parameterize(sMesh, Parameterizer(), bhd, uv_pm);
|
|
break;
|
|
}
|
|
case PARAM_LSC:
|
|
{
|
|
new_item_name = tr("%1 (parameterized (LSC))").arg(poly_item->name());
|
|
std::cout << "Parameterize (LSC)..." << std::endl;
|
|
typedef SMP::LSCM_parameterizer_3<Seam_mesh> Parameterizer;
|
|
status = SMP::parameterize(sMesh, Parameterizer(), bhd, uv_pm);
|
|
break;
|
|
}
|
|
case PARAM_DAP:
|
|
{
|
|
new_item_name = tr("%1 (parameterized (DAP))").arg(poly_item->name());
|
|
std::cout << "Parameterize (DAP)..." << std::endl;
|
|
typedef SMP::Discrete_authalic_parameterizer_3<Seam_mesh> Parameterizer;
|
|
status = SMP::parameterize(sMesh, Parameterizer(), bhd, uv_pm);
|
|
break;
|
|
}
|
|
case PARAM_ARAP:
|
|
{
|
|
new_item_name = tr("%1 (parameterized (ARAP))").arg(poly_item->name());
|
|
std::cout << "Parameterize (ARAP)..." << std::endl;
|
|
|
|
QDialog dialog(mw);
|
|
Ui::ARAP_dialog ui;
|
|
ui.setupUi(&dialog);
|
|
connect(ui.buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept()));
|
|
connect(ui.buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject()));
|
|
|
|
// Get values
|
|
QApplication::restoreOverrideCursor();
|
|
|
|
int i = dialog.exec();
|
|
if (i == QDialog::Rejected)
|
|
return;
|
|
|
|
FT lambda = ui.lambdaSpinBox->value();
|
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
|
|
|
typedef SMP::ARAP_parameterizer_3<Seam_mesh> Parameterizer;
|
|
status = SMP::parameterize(sMesh, Parameterizer(lambda), bhd, uv_pm);
|
|
break;
|
|
}
|
|
case PARAM_OTE:
|
|
{
|
|
new_item_name = tr("%1 (parameterized (OTE))").arg(poly_item->name());
|
|
std::cout << "Parameterize (OTE)..." << std::endl;
|
|
|
|
// OTE cannot handle multiple connected components right now
|
|
// @todo (need to remove the assertions such as cones.size() == 4
|
|
// and check where and when cones are used (passed by ID, for ex.?))
|
|
if(number_of_components != 1) {
|
|
std::cerr << "Orbifold Tutte Embedding can only handle one connected component at the moment" << std::endl;
|
|
return;
|
|
}
|
|
|
|
typedef SMP::Orbifold_Tutte_parameterizer_3<Seam_mesh> Parameterizer;
|
|
|
|
QDialog dialog(mw);
|
|
Ui::OTE_dialog ui;
|
|
ui.setupUi(&dialog);
|
|
connect(ui.buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept()));
|
|
connect(ui.buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject()));
|
|
|
|
// Get values
|
|
QApplication::restoreOverrideCursor();
|
|
|
|
int i = dialog.exec();
|
|
if (i == QDialog::Rejected)
|
|
return;
|
|
|
|
SMP::Orbifold_type orb = static_cast<SMP::Orbifold_type>(ui.OrbComboBox->currentIndex());
|
|
std::cout << "selected orbifold type: " << ui.OrbComboBox->currentText().toStdString() << std::endl;
|
|
|
|
if((unordered_cones.size() != 3 && unordered_cones.size() != 4) ||
|
|
(unordered_cones.size() == 3 && orb == SMP::Parallelogram ) ||
|
|
(unordered_cones.size() == 4 && orb != SMP::Parallelogram)) {
|
|
std::cerr << "Incompatible orbifold type and number of cones" << std::endl;
|
|
std::cerr << "Types I, II & III require 3 selected vertices" << std::endl;
|
|
std::cerr << "Type IV requires 4 selected vertices" << std::endl;
|
|
return;
|
|
}
|
|
|
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
|
|
|
// Now, parameterize
|
|
Parameterizer parameterizer(orb);
|
|
|
|
// mark cones in the seam mesh
|
|
typedef boost::unordered_map<s_vertex_descriptor, SMP::Cone_type> Cones;
|
|
Cones cmap;
|
|
|
|
if(!SMP::internal::locate_unordered_cones<Seam_mesh,
|
|
boost::unordered_set<T_vertex_descriptor>,
|
|
Cones>(sMesh, unordered_cones, cmap))
|
|
return;
|
|
|
|
// vimap and uvmap
|
|
typedef boost::unordered_map<s_vertex_descriptor, int> Indices;
|
|
Indices indices;
|
|
CGAL::Polygon_mesh_processing::connected_component(
|
|
face(opposite(bhd, sMesh), sMesh),
|
|
sMesh,
|
|
boost::make_function_output_iterator(
|
|
SMP::internal::Index_map_filler<Seam_mesh, Indices>(sMesh, indices)));
|
|
boost::associative_property_map<Indices> vimap(indices);
|
|
|
|
// Call to parameterizer
|
|
status = parameterizer.parameterize(sMesh, bhd, cmap, uv_pm, vimap);
|
|
break;
|
|
}
|
|
case PARAM_BTP:
|
|
{
|
|
std::cout << "Parameterize (BTP)..." << std::endl;
|
|
new_item_name = tr("%1 (parameterized (BTP))").arg(poly_item->name());
|
|
typedef SMP::Barycentric_mapping_parameterizer_3<Seam_mesh> Parameterizer;
|
|
status = SMP::parameterize(sMesh, Parameterizer(), bhd, uv_pm);
|
|
break;
|
|
}
|
|
} //end switch
|
|
|
|
std::cout << "Connected component " << current_component << ": ";
|
|
if(status == SMP::OK) {
|
|
std::cout << "success (in " << time.elapsed() << " ms)" << std::endl;
|
|
} else {
|
|
std::cout << "failure: " << SMP::get_error_message(status) << std::endl;
|
|
return;
|
|
}
|
|
|
|
if(status != SMP::OK)
|
|
break;
|
|
|
|
} //end for each component
|
|
|
|
QApplication::restoreOverrideCursor();
|
|
QPointF min(FLT_MAX, FLT_MAX), max(-FLT_MAX, -FLT_MAX);
|
|
#ifndef USE_SURFACE_MESH
|
|
Base_face_graph::Halfedge_iterator it1;
|
|
Textured_polyhedron::Halfedge_iterator it2;
|
|
for(it1 = tMesh.halfedges_begin(),
|
|
it2 = tpMesh->halfedges_begin();
|
|
it1 != tMesh.halfedges_end()&&
|
|
it2 != tpMesh->halfedges_end();
|
|
++it1, ++it2)
|
|
{
|
|
Seam_mesh::halfedge_descriptor hd(it1);
|
|
FT u = uv_pm[target(hd, sMesh)].x();
|
|
FT v = uv_pm[target(hd, sMesh)].y();
|
|
it2->u() = u;
|
|
it2->v() = v;
|
|
if(u<min.x())
|
|
min.setX(u);
|
|
if(u>max.x())
|
|
max.setX(u);
|
|
if(v<min.y())
|
|
min.setY(v);
|
|
if(v>max.y())
|
|
max.setY(v);
|
|
}
|
|
#else
|
|
SMesh::Property_map<halfedge_descriptor,std::pair<float, float> > uv;
|
|
uv = tMesh.add_property_map<halfedge_descriptor,std::pair<float, float> >("h:uv",std::make_pair(0.0f,0.0f)).first;
|
|
Base_face_graph::Halfedge_iterator it;
|
|
for(it = tMesh.halfedges_begin();
|
|
it != tMesh.halfedges_end();
|
|
++it)
|
|
{
|
|
Seam_mesh::halfedge_descriptor hd(*it);
|
|
FT u = uv_pm[target(hd, sMesh)].x();
|
|
FT v = uv_pm[target(hd, sMesh)].y();
|
|
put(uv, *it, std::make_pair(static_cast<float>(u),static_cast<float>(v)));
|
|
if(u<min.x())
|
|
min.setX(u);
|
|
if(u>max.x())
|
|
max.setX(u);
|
|
if(v<min.y())
|
|
min.setY(v);
|
|
if(v>max.y())
|
|
max.setY(v);
|
|
}
|
|
|
|
#endif
|
|
|
|
Components* components = new Components(0);
|
|
components->resize(number_of_components);
|
|
boost::graph_traits<Base_face_graph>::face_iterator bfit;
|
|
#ifdef USE_SURFACE_MESH
|
|
for(bfit = faces(tMesh).begin();
|
|
bfit != faces(tMesh).end();
|
|
++bfit)
|
|
{
|
|
components->at(fccmap[*bfit]).insert(*bfit);
|
|
}
|
|
|
|
Scene_textured_facegraph_item* new_item = new Scene_textured_facegraph_item(tMesh);
|
|
UVItem *projection = new UVItem(components,new_item->textured_face_graph(), uv_borders, QRectF(min, max));
|
|
projection->set_item_name(new_item_name);
|
|
#else
|
|
boost::graph_traits<Base_face_graph>::face_iterator tfit;
|
|
for(bfit = faces(tMesh).begin(), tfit = faces(*tpMesh).begin();
|
|
bfit != faces(tMesh).end() && tfit != faces(*tpMesh).end();
|
|
++bfit, ++tfit)
|
|
{
|
|
components->at(fccmap[*bfit]).insert(*tfit);
|
|
}
|
|
|
|
UVItem *projection = new UVItem(components,tpMesh, uv_borders, QRectF(min, max));
|
|
projection->set_item_name(new_item_name);
|
|
Scene_textured_facegraph_item* new_item = new Scene_textured_facegraph_item(tpMesh);
|
|
#endif
|
|
new_item->setName(new_item_name);
|
|
new_item->setColor(Qt::white);
|
|
new_item->setRenderingMode(poly_item->renderingMode());
|
|
connect( new_item, SIGNAL(selectionChanged()),
|
|
this, SLOT(replacePolyline()) );
|
|
poly_item->setVisible(false);
|
|
scene->itemChanged(index);
|
|
scene->addItem(new_item);
|
|
if(!graphics_scene->items().empty())
|
|
graphics_scene->removeItem(graphics_scene->items().first());
|
|
graphics_scene->addItem(projection);
|
|
projections[new_item] = projection;
|
|
if(current_uv_item)
|
|
qobject_cast<Scene_textured_facegraph_item*>(projections.key(current_uv_item))->add_border_edges(std::vector<float>(0));
|
|
current_uv_item = projection;
|
|
qobject_cast<Scene_textured_facegraph_item*>(projections.key(current_uv_item))->add_border_edges(current_uv_item->concatenated_borders());
|
|
if(dock_widget->isHidden())
|
|
dock_widget->setVisible(true);
|
|
dock_widget->setWindowTitle(tr("UVMapping for %1").arg(new_item->name()));
|
|
ui_widget.component_numberLabel->setText(QString("Component : %1/%2").arg(current_uv_item->current_component()+1).arg(current_uv_item->number_of_components()));
|
|
ui_widget.graphicsView->fitInView(projection->boundingRect(), Qt::KeepAspectRatio);
|
|
|
|
QApplication::restoreOverrideCursor();
|
|
|
|
}
|
|
|
|
void Polyhedron_demo_parameterization_plugin::on_actionMVC_triggered()
|
|
{
|
|
std::cerr << "MVC...";
|
|
parameterize(PARAM_MVC);
|
|
}
|
|
|
|
void Polyhedron_demo_parameterization_plugin::on_actionDCP_triggered()
|
|
{
|
|
std::cerr << "DCP...";
|
|
parameterize(PARAM_DCP);
|
|
}
|
|
|
|
void Polyhedron_demo_parameterization_plugin::on_actionLSC_triggered()
|
|
{
|
|
std::cerr << "LSC...";
|
|
parameterize(PARAM_LSC);
|
|
}
|
|
|
|
void Polyhedron_demo_parameterization_plugin::on_actionDAP_triggered()
|
|
{
|
|
std::cerr << "DAP...";
|
|
parameterize(PARAM_DAP);
|
|
}
|
|
|
|
void Polyhedron_demo_parameterization_plugin::on_actionARAP_triggered()
|
|
{
|
|
std::cerr << "ARAP...";
|
|
parameterize(PARAM_ARAP);
|
|
}
|
|
|
|
void Polyhedron_demo_parameterization_plugin::on_actionOTE_triggered()
|
|
{
|
|
std::cerr << "OTE...";
|
|
parameterize(PARAM_OTE);
|
|
}
|
|
|
|
void Polyhedron_demo_parameterization_plugin::on_actionBTP_triggered()
|
|
{
|
|
std::cerr << "BTP...";
|
|
parameterize(PARAM_BTP);
|
|
}
|
|
|
|
#include "Parameterization_plugin.moc"
|