diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt index 9be832c313a..3832d1401d1 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt @@ -109,6 +109,9 @@ target_link_libraries(random_perturbation_plugin PUBLIC scene_surface_mesh_item polyhedron_demo_plugin(degenerated_faces_plugin Degenerated_faces_plugin) target_link_libraries(degenerated_faces_plugin PUBLIC scene_surface_mesh_item scene_selection_item) +qt5_wrap_ui( engravUI_FILES Engrave_dock_widget.ui ) +polyhedron_demo_plugin(engrave_text_plugin Engrave_text_plugin ${engravUI_FILES}) +target_link_libraries(engrave_text_plugin PUBLIC scene_surface_mesh_item scene_selection_item scene_polylines_item) polyhedron_demo_plugin(extrude_plugin Extrude_plugin) target_link_libraries(extrude_plugin PUBLIC scene_surface_mesh_item scene_selection_item) diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Engrave_dock_widget.ui b/Polyhedron/demo/Polyhedron/Plugins/PMP/Engrave_dock_widget.ui new file mode 100644 index 00000000000..a893a256196 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Engrave_dock_widget.ui @@ -0,0 +1,316 @@ + + + EngraveWidget + + + + 0 + 0 + 293 + 515 + + + + Engraving + + + + + + + An Example Text + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Visualize + + + + + + + false + + + Engrave + + + + + + + false + + + Generate Text Mesh + + + + + + + Reset + + + + + + + + + + + + + + + + + :/cgal/icons/resources/up.png:/cgal/icons/resources/up.png + + + + + + + -179 + + + 179 + + + Qt::Horizontal + + + + + + + + + + + :/cgal/icons/resources/right_arrow.png:/cgal/icons/resources/right_arrow.png + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + :/cgal/icons/resources/down.png:/cgal/icons/resources/down.png + + + + + + + Scaling factor in X: + + + + + + + + + + + :/cgal/icons/resources/left_arrow.png:/cgal/icons/resources/left_arrow.png + + + + + + + Rotation degree: + + + + + + + 2000 + + + 1 + + + 1000 + + + 1000 + + + Qt::Horizontal + + + + + + + 2000 + + + 10 + + + 1000 + + + Qt::Horizontal + + + + + + + Scaling factor in Y: + + + + + + + 1 + + + 15 + + + Qt::Horizontal + + + + + + + Text Precision + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Engraving Depth + + + + + + 10000 + + + 1000 + + + Qt::Horizontal + + + + + + + 10000 + + + 1000 + + + Qt::Horizontal + + + + + + + Inside depth: + + + + + + + Outside depth: + + + + + + + Uniform letter mode + + + + + + + + + + + + + + + + + + + diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Engrave_text_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Engrave_text_plugin.cpp new file mode 100644 index 00000000000..6cad4ed03c9 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Engrave_text_plugin.cpp @@ -0,0 +1,931 @@ +//General Plugin Data +#include +#include + +#include "ui_Engrave_dock_widget.h" +//Items +#include "Scene_surface_mesh_item.h" +#include "Scene_polyhedron_selection_item.h" +#include "Scene_polylines_item.h" +#include "Messages_interface.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +using namespace CGAL::Three; +namespace SMP = CGAL::Surface_mesh_parameterization; +typedef EPICK::Point_2 Point_2; +typedef EPICK::Point_3 Point_3; + +typedef boost::graph_traits:: +edge_descriptor edge_descriptor; +typedef boost::graph_traits:: +halfedge_descriptor halfedge_descriptor; +typedef boost::graph_traits:: +vertex_descriptor vertex_descriptor; + +typedef boost::unordered_set:: +face_descriptor> Component; + +struct FaceInfo2 +{ + FaceInfo2(){} + int nesting_level; + bool in_domain(){ + return nesting_level%2 == 1; + } +}; + +template +struct Bot +{ + Bot(NMAP nmap, + double d, + PMAP pmap):d(d), + pmap(pmap), + nmap(nmap){} + template + void operator()(const T& v1,VD v2) const + { + put(pmap, v2, get(pmap, v2)-d*get(nmap, v1)); + } + double d; + PMAP pmap; + NMAP nmap; + +}; + +template +struct Top +{ + Top(NMAP nmap, + PMAP pmap, + double d):d(d), + nmap(nmap), + pmap(pmap){} + + template + void operator()(const T& v1, VD v2) const + { + put(pmap, v2, get(pmap, v2)+d*get(nmap, v1)); + } + double d; + NMAP nmap; + PMAP pmap; +}; + +typedef EPICK Gt; +typedef CGAL::Triangulation_vertex_base_2 Vb; +typedef CGAL::Triangulation_face_base_with_info_2 Fbb; +typedef CGAL::Constrained_triangulation_face_base_2 Fb; +typedef CGAL::Triangulation_data_structure_2 TDS; +typedef CGAL::No_intersection_tag Tag; +typedef CGAL::Constrained_Delaunay_triangulation_2 CDT; + +//Parameterization and text displaying +class ParamItem : public QGraphicsItem +{ +public : + ParamItem(Component* component, + const std::vector > &polylines, + EPICK::Aff_transformation_2 transfo, + SMesh* graph, + QRectF brect) + : + QGraphicsItem(), + bounding_rect(brect), + component(component), + polylines(polylines), + graph(graph), + transfo(transfo){} + + ~ParamItem() + { + delete component; + } + + QRectF boundingRect() const + { + return bounding_rect; + } + + void set_transfo(EPICK::Aff_transformation_2 t){ transfo = t;} + + 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); + SMesh::Property_map > uv; + uv = graph->add_property_map > + ("h:uv",std::make_pair(0.0f,0.0f)).first; + for( Component::iterator + fi = component->begin(); + fi != component->end(); + ++fi) + { + boost::graph_traits::face_descriptor f(*fi); + QPointF points[3]; + boost::graph_traits::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); + painter->drawPolygon(points,3); + } + + pen.setColor(Qt::red); + pen.setWidth(0); + painter->setPen(pen); + for(std::size_t i =0; i points; + points.reserve(polylines[i].size()); + for(std::size_t j =0; jdrawPolyline(points.data(), static_cast(points.size())); + } + } + +private: + QString texMesh_name; + QRectF bounding_rect; + Component* component; + const std::vector >& polylines; + + SMesh* graph; + EPICK::Aff_transformation_2 transfo; +}; + +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(obj); + if(v == NULL) { + QWidget* viewport = qobject_cast(obj); + if(viewport == NULL) { + return false; + } + v = qobject_cast(viewport->parent()); + if(v == NULL) { + return false; + } + } + switch(ev->type()) + { + case QEvent::MouseMove: { + QMouseEvent* me = static_cast(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(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; +}; + + +class EngraveWidget : + public QDockWidget, + public Ui::EngraveWidget +{ +public: + EngraveWidget(QString name, QWidget *parent) + :QDockWidget(name,parent) + { + setupUi(this); + } +}; + +class Q_DECL_EXPORT Engrave_text_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") + +private: + typedef CGAL::Surface_mesh_shortest_path_traits SP_traits; + typedef CGAL::Surface_mesh_shortest_path Surface_mesh_shortest_path; + typedef Surface_mesh_shortest_path::Face_location Face_location; + typedef CGAL::AABB_face_graph_triangle_primitive Primitive; + typedef CGAL::AABB_traits Tree_traits; + typedef CGAL::AABB_tree Tree; + typedef EPICK::Point_3 Point_3; + Messages_interface* messages; + +public : + + void init(QMainWindow*, + CGAL::Three::Scene_interface*, + Messages_interface* m) Q_DECL_OVERRIDE{ + //get refs + this->scene = Three::scene(); + this->mw = Three::mainWindow(); + messages = m; + + //action + QAction* actionFitText= new QAction("Fit Text", mw); + connect(actionFitText, SIGNAL(triggered()), + this, SLOT(showWidget())); + _actions << actionFitText; + //widget + dock_widget = new EngraveWidget("Engraving", mw); + dock_widget->setVisible(false); // do not show at the beginning + addDockWidget(dock_widget); + connect(dock_widget->visualizeButton, &QPushButton::clicked, + this, &Engrave_text_plugin::visualize); + connect(dock_widget->engraveButton, &QPushButton::clicked, + this, &Engrave_text_plugin::engrave); + connect(dock_widget->text_meshButton, &QPushButton::clicked, + this, &Engrave_text_plugin::generateTextItem); + connect(dock_widget->letter_checkBox, &QCheckBox::toggled, + this, &Engrave_text_plugin::generateTextItem); + + //items + visu_item = nullptr; + sel_item = nullptr; + textMesh = nullptr; + sm = nullptr; + + //transfo + angle = 0.0; + scalX=1.0; + scalY=1.0; + translation = EPICK::Vector_2(0,0); + pointsize = 15; + locked = false; + connect(dock_widget->text_prec_slider, &QSlider::valueChanged, + this, [this](){ + pointsize = dock_widget->text_prec_slider->value(); + scene->setSelectedItem(scene->item_id(sel_item)); + visualize(); + }); + connect(dock_widget->scalX_slider, &QSlider::valueChanged, + this, [this](){ + scalX = dock_widget->scalX_slider->value()/1000.0; + scene->setSelectedItem(scene->item_id(sel_item)); + visualize(); + }); + connect(dock_widget->scalY_slider, &QSlider::valueChanged, + this, [this](){ + scalY = dock_widget->scalY_slider->value()/1000.0; + scene->setSelectedItem(scene->item_id(sel_item)); + visualize(); + }); + + connect(dock_widget->bot_slider, &QSlider::valueChanged, + this, [this](){ + if(textMesh) + generateTextItem(); + }); + + connect(dock_widget->top_slider, &QSlider::valueChanged, + this, [this](){ + if(textMesh) + generateTextItem(); + }); + + connect(dock_widget->reset_button, &QPushButton::clicked, + this, [this](){ + cleanup(); + }); + + connect(dock_widget->t_up_pushButton, &QPushButton::clicked, + this, [this](){ + translation += EPICK::Vector_2(0,0.005); + scene->setSelectedItem(scene->item_id(sel_item)); + visualize(); + }); + + connect(dock_widget->t_down_pushButton, &QPushButton::clicked, + this, [this](){ + translation -= EPICK::Vector_2(0,0.005); + scene->setSelectedItem(scene->item_id(sel_item)); + visualize(); + }); + + connect(dock_widget->t_right_pushButton, &QPushButton::clicked, + this, [this](){ + translation += EPICK::Vector_2(0.005,0); + scene->setSelectedItem(scene->item_id(sel_item)); + visualize(); + }); + + connect(dock_widget->t_left_pushButton, &QPushButton::clicked, + this, [this](){ + translation -= EPICK::Vector_2(0.005,0); + scene->setSelectedItem(scene->item_id(sel_item)); + visualize(); + }); + connect(dock_widget->rot_slider, &QSlider::valueChanged, + this, [this](){ + if(!locked) + { + angle = dock_widget->rot_slider->value() * CGAL_PI/180.0; + scene->setSelectedItem(scene->item_id(sel_item)); + visualize(); + } + }); + graphics_scene = new QGraphicsScene(dock_widget); + dock_widget->graphicsView->setScene(graphics_scene); + dock_widget->graphicsView->setRenderHints(QPainter::Antialiasing); + navigation = new Navigation(); + dock_widget->graphicsView->installEventFilter(navigation); + dock_widget->graphicsView->viewport()->installEventFilter(navigation); + } + bool applicable(QAction*) const Q_DECL_OVERRIDE + { + return qobject_cast + (scene->item(scene->mainSelectionIndex())); + } + QList actions() const Q_DECL_OVERRIDE{ + return _actions; + } +public Q_SLOTS: + void showWidget() + { + dock_widget->setVisible(!dock_widget->isVisible()); + } + + void visualize() { + if(!sel_item) + sel_item = + qobject_cast + (scene->item(scene->mainSelectionIndex())); + if(!sel_item) + return; + if(sel_item->selected_facets.empty()) + { + cleanup(); + return; + } + if(!CGAL::is_closed(*sel_item->polyhedron())) + { + cleanup(); + return; + } + if(visu_item) + scene->erase(scene->item_id(visu_item)); + visu_item = nullptr; + + if(!sm) + { + sm = new SMesh(); + sel_item->export_selected_facets_as_polyhedron(sm); + SMesh::Halfedge_index hd = + CGAL::Polygon_mesh_processing::longest_border(*sm).first; + SMesh::Property_map uv_map = + sm->add_property_map("v:uv").first; + + // Parameterized bool pmap + boost::unordered_set vs; + SMP::internal::Bool_property_map< boost::unordered_set > vpm(vs); + + // Parameterizer + SMP::ARAP_parameterizer_3 parameterizer; + + SMP::Error_code status = parameterizer.parameterize(*sm, hd, uv_map, + get(boost::vertex_index, *sm), vpm); + if(status != SMP::OK) { + std::cout << "Encountered a problem: " << status << std::endl; + cleanup(); + return ; + } + + std::cout << "Parameterized with ARAP (SM) computed." << std::endl; + xmin = std::numeric_limits::max(); + xmax = std::numeric_limits::min(); + ymin = std::numeric_limits::max(); + ymax = std::numeric_limits::min(); + uv_map_3 = + sm->add_property_map("v:uv3").first; + for(SMesh::Vertex_index v : sm->vertices()) + { + uv_map_3[v] = Point_3(uv_map[v][0], uv_map[v] + [1], 0); + if(uv_map[v][0] > xmax) + xmax = uv_map[v][0]; + if(uv_map[v][0] < xmin) + xmin = uv_map[v][0]; + + if(uv_map[v][1] > ymax) + ymax = uv_map[v][1]; + if(uv_map[v][1] < ymin) + ymin = uv_map[v][1]; + } + + CGAL::linear_least_squares_fitting_2( + uv_map.begin(), + uv_map.end(), + bf_line, + CGAL::Dimension_tag<0>()); + + EPICK::Vector_2 A(bf_line.to_vector()), + B(EPICK::Point_2(0,0), + EPICK::Point_2(1,0)); + if (A.x()<0) A=-A; + angle = std::acos(A.x()/CGAL::sqrt(A.squared_length())); + if ( A.y()<0 ) angle+=3*CGAL_PI/2.; + if (angle>2*CGAL_PI) angle-=2*CGAL_PI; + + locked = true; + dock_widget->rot_slider->setSliderPosition(angle*180.0/CGAL_PI); + locked = false; + } + //create Text Polyline + QPainterPath path; + QFont font; + font.setPointSize(pointsize); + path.addText(QPoint(xmin,ymin), font, dock_widget->lineEdit->text()); + QList polys = path.toSubpathPolygons(); + polylines.clear(); + float pxmin(8000),pxmax(-8000), + pymin(8000), pymax(-8000); + + Q_FOREACH(QPolygonF poly, polys){ + Q_FOREACH(QPointF pf, poly) + { + EPICK::Point_2 v = EPICK::Point_2(pf.x(),-pf.y()); + if(v.x() < pxmin) + pxmin = v.x(); + if(v.x() > pxmax) + pxmax = v.x(); + if(v.y() < pymin) + pymin = v.y(); + if(v.y() > pymax) + pymax = v.y(); + } + } + Q_FOREACH(QPolygonF poly, polys){ + polylines.push_back(std::vector()); + Q_FOREACH(QPointF pf, poly) + { + EPICK::Point_2 v = EPICK::Point_2(pf.x(),-pf.y()); + polylines.back().push_back(EPICK::Point_2(v.x()*(xmax-xmin)/(pxmax-pxmin) +xmin , + v.y()*(ymax-ymin)/(pymax-pymin)+ymin + )); + } + } + + // build AABB-tree for face location queries + Tree aabb_tree(faces(*sm).first, faces(*sm).second, *sm, uv_map_3); + + visu_item = new Scene_polylines_item; + + + // compute 3D coordinates + transfo = + EPICK::Aff_transformation_2(CGAL::TRANSLATION, + EPICK::Vector_2((xmax-xmin)/2+xmin, + (ymax-ymin)/2+ymin)+ translation) + * EPICK::Aff_transformation_2(CGAL::ROTATION,sin(angle), cos(angle)) + * EPICK::Aff_transformation_2(scalX, 0.0,0.0,scalY) + * EPICK::Aff_transformation_2(CGAL::TRANSLATION, + EPICK::Vector_2(-(xmax-xmin)/2-xmin, + -(ymax-ymin)/2-ymin)); + BOOST_FOREACH(const std::vector& polyline, polylines) + { + visu_item->polylines.push_back(std::vector()); + BOOST_FOREACH(const EPICK::Point_2& p, polyline) + { + EPICK::Point_2 p_2 = transfo.transform(p); + + Face_location loc = Surface_mesh_shortest_path::locate( + Point_3(p_2.x(), p_2.y(), 0), + aabb_tree, *sm, uv_map_3); + visu_item->polylines.back().push_back( + Surface_mesh_shortest_path::point(loc.first, loc.second, *sm, sm->points())); + } + } + visu_item->setName("Text"); + visu_item->setColor(QColor(Qt::red)); + scene->addItem(visu_item); + dock_widget->engraveButton->setEnabled(true); + dock_widget->text_meshButton->setEnabled(true); + + if(graphics_scene->items().empty()) + { + Component* component = new Component(); + face_iterator bfit; + for(bfit = faces(*sm).begin(); + bfit != faces(*sm).end(); + ++bfit) + { + component->insert(*bfit); + } + SMesh::Property_map > uv; + uv = sm->add_property_map >( + "h:uv",std::make_pair(0.0f,0.0f)).first; + SMesh::Halfedge_iterator it; + SMesh::Property_map uv_map = + sm->property_map("v:uv").first; + for(it = sm->halfedges_begin(); + it != sm->halfedges_end(); + ++it) + { + halfedge_descriptor hd(*it); + EPICK::FT u = uv_map[target(hd, *sm)].x(); + EPICK::FT v = uv_map[target(hd, *sm)].y(); + put(uv, *it, std::make_pair(static_cast(u),static_cast(v))); + } + + //ParamItem does not take ownership of text_mesh_bottom + ParamItem *param_item= new ParamItem(component, polylines, transfo, sm, + QRectF(QPointF(xmin, -ymax), QPointF(xmax, -ymin))); + graphics_scene->addItem(param_item); + dock_widget->graphicsView->fitInView(param_item->boundingRect(), Qt::KeepAspectRatio); + } + else + { + ParamItem* param_item = static_cast(graphics_scene->items().first()); + param_item->set_transfo(transfo); + dock_widget->graphicsView->activateWindow(); + graphics_scene->update(); + } + // dock_widget->visualizeButton->setEnabled(false); + } + + void create_text_mesh(SMesh& text_mesh) + { + if(!visu_item) + return; + if(!sel_item) + return; + if(sel_item->selected_facets.empty()) + return; + if(!CGAL::is_closed(*sel_item->polyhedron())) + return; + CDT cdt; + //polylines is duplicated so the transformation is only performed once + std::vector > local_polylines + = polylines; + try{ + for(std::size_t i = 0; + i < local_polylines.size(); ++i) + { + std::vector& points = local_polylines[i]; + for(std::size_t j = 0; j< points.size(); ++j) + { + Point_2 &p = points[j]; + p = transfo.transform(p); + } + cdt.insert_constraint(points.begin(),points.end()); + } + }catch(std::runtime_error&) + { + QApplication::restoreOverrideCursor(); + throw; + } + if (cdt.dimension()!=2){ + QApplication::restoreOverrideCursor(); + std::cout << "Triangulation is not of dimension 2" << std::endl; + return; + } + CGAL::Bbox_2 bbox= CGAL::bbox_2(local_polylines.front().begin(), + local_polylines.front().end(), + EPICK()); + Q_FOREACH(const std::vector& points, + local_polylines) + { + bbox += CGAL::bbox_2(points.begin(), points.end(), EPICK()); + } + mark_nested_domains(cdt); + + SMesh text_mesh_bottom; + cdt2_to_face_graph(cdt, + text_mesh_bottom); + typedef boost::property_map::type VPMap; + typedef SMesh::Property_map NPMAP; + NPMAP vnormals = + text_mesh_bottom.add_property_map("v:normal").first; + + if(!dock_widget->letter_checkBox->isChecked()) + { + CGAL::Polygon_mesh_processing::compute_vertex_normals(text_mesh_bottom, vnormals); + } + else{ + // \todo Computing normals before the final + // mesh would be better. + + //foreach CC + SMesh::Property_map fcmap = + text_mesh_bottom.add_property_map("f:cc", 0).first; + std::size_t nb_cc = PMP::connected_components(text_mesh_bottom, + fcmap); + for(std::size_t cc = 0; cc fmesh(text_mesh_bottom, + static_cast(cc), + fcmap); + BOOST_FOREACH(vertex_descriptor vd, vertices(fmesh)) + { + normal += CGAL::Polygon_mesh_processing::compute_vertex_normal(vd, fmesh); + } + normal /= CGAL::sqrt(normal.squared_length()); + BOOST_FOREACH(vertex_descriptor vd, vertices(fmesh)) + { + put(vnormals, vd, normal); + } + } + } + Bot bot(vnormals, dock_widget->bot_slider->value()/100000.0, + get(CGAL::vertex_point, text_mesh)); + Top top(vnormals, get(CGAL::vertex_point, text_mesh), + dock_widget->top_slider->value()/100000.0); + PMP::extrude_mesh(text_mesh_bottom, text_mesh, bot, top); + } + + void engrave() { + QApplication::setOverrideCursor(Qt::WaitCursor); + SMesh text_mesh_complete; + create_text_mesh(text_mesh_complete); + + if (PMP::does_self_intersect(text_mesh_complete)) + { + QApplication::restoreOverrideCursor(); + messages->information("Error: text mesh self-intersects!"); + return; + } + + SMesh result; + CGAL::copy_face_graph(*sel_item->polyhedron(), result); + bool OK = PMP::corefine_and_compute_difference(result, text_mesh_complete, result); + + if (!OK) + { + QApplication::restoreOverrideCursor(); + messages->information("Error: the output mesh is not manifold!"); + return; + } + + CGAL::Polygon_mesh_processing::triangulate_faces(result); + Scene_surface_mesh_item* result_item = new Scene_surface_mesh_item( + result); + scene->addItem(result_item); + graphics_scene->clear(); + cleanup(); + if(textMesh) + { + textMesh->setVisible(false); + } + QApplication::restoreOverrideCursor(); + dock_widget->engraveButton->setEnabled(false); + dock_widget->text_meshButton->setEnabled(false); + dock_widget->visualizeButton->setEnabled(true); + } + + void generateTextItem() + { + QApplication::setOverrideCursor(Qt::WaitCursor); + + if(textMesh) + { + textMesh->face_graph()->clear(); + create_text_mesh(*textMesh->face_graph()); + textMesh->invalidateOpenGLBuffers(); + } + else + { + SMesh text_mesh; + create_text_mesh(text_mesh); + textMesh = new Scene_surface_mesh_item(text_mesh); + connect(textMesh, &Scene_surface_mesh_item::aboutToBeDestroyed, + this, [this](){ + textMesh = nullptr;}); + textMesh->setName("Extruded Text"); + scene->addItem(textMesh); + } + QApplication::restoreOverrideCursor(); + } + + void closure()Q_DECL_OVERRIDE + { + dock_widget->hide(); + } + +private: + template + void + mark_domains(CDT& ct, + typename CDT::Face_handle start, + int index, + std::list& border ) + { + if(start->info().nesting_level != -1){ + return; + } + std::list queue; + queue.push_back(start); + while(! queue.empty()){ + typename CDT::Face_handle fh = queue.front(); + queue.pop_front(); + if(fh->info().nesting_level == -1){ + fh->info().nesting_level = index; + for(int i = 0; i < 3; i++){ + typename CDT::Edge e(fh,i); + typename CDT::Face_handle n = fh->neighbor(i); + if(n->info().nesting_level == -1){ + if(ct.is_constrained(e)) border.push_back(e); + else queue.push_back(n); + } + } + } + } + } + + + template + void + mark_nested_domains(CDT& cdt) + { + for(typename CDT::All_faces_iterator it = cdt.all_faces_begin(); it != + cdt.all_faces_end(); ++it){ + it->info().nesting_level = -1; + } + std::list border; + mark_domains(cdt, cdt.infinite_face(), 0, border); + while(! border.empty()){ + typename CDT::Edge e = border.front(); + border.pop_front(); + typename CDT::Face_handle n = e.first->neighbor(e.second); + if(n->info().nesting_level == -1){ + mark_domains(cdt, n, e.first->info().nesting_level+1, border); + } + } + } + + template + void cdt2_to_face_graph(const CDT& cdt, + TriangleMesh& tm) + { + + Tree aabb_tree(faces(*sm).first, faces(*sm).second, *sm, uv_map_3); + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + + typedef std::map Map; + Map descriptors; + for (typename CDT::Finite_faces_iterator fit=cdt.finite_faces_begin(), + fit_end=cdt.finite_faces_end(); + fit!=fit_end; ++fit) + { + if (!fit->info().in_domain()) continue; + CGAL::cpp11::array vds; + for(int i=0; i<3; ++i) + { + typename Map::iterator it; + bool insert_ok; + boost::tie(it,insert_ok) = + descriptors.insert(std::make_pair(fit->vertex(i),vertex_descriptor())); + if (insert_ok){ + const EPICK::Point_2& pt=fit->vertex(i)->point(); + Face_location loc = Surface_mesh_shortest_path::locate( + Point_3(pt.x(), pt.y(), 0), + aabb_tree, *sm, uv_map_3); + it->second = add_vertex(Surface_mesh_shortest_path::point(loc.first, loc.second, + *sm, sm->points()), tm); + } + vds[i]=it->second; + } + + CGAL::Euler::add_face(vds, tm); + } + } + + void cleanup() + { + dock_widget->scalX_slider->setValue(1000); + dock_widget->scalY_slider->setValue(1000); + dock_widget->rot_slider->setValue(0); + translation = EPICK::Vector_2(0,0); + uv_map_3.reset(); + graphics_scene->clear(); + if(sel_item) + { + scene->erase(scene->item_id(sel_item)); + sel_item =nullptr; + } + if(sm) + { + delete sm; + sm = nullptr; + } + if(visu_item) + { + scene->erase(scene->item_id(visu_item)); + visu_item = nullptr; + } + } + + QList _actions; + EngraveWidget* dock_widget; + Scene_polylines_item* visu_item; + Scene_polyhedron_selection_item* sel_item; + Scene_surface_mesh_item* textMesh; + double angle; + double scalX; + double scalY; + EPICK::Vector_2 translation; + EPICK::Aff_transformation_2 transfo; + std::vector > polylines; + SMesh::Property_map uv_map_3; + SMesh* sm; + float xmin, xmax, ymin, ymax; + int pointsize; + bool locked; + EPICK::Line_2 bf_line; + QGraphicsScene *graphics_scene; + Navigation* navigation; +}; +#include "Engrave_text_plugin.moc" +