diff --git a/Polyhedron/demo/Polyhedron/CMakeLists.txt b/Polyhedron/demo/Polyhedron/CMakeLists.txt index c482d9904bb..bd145cf1a44 100644 --- a/Polyhedron/demo/Polyhedron/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/CMakeLists.txt @@ -109,6 +109,7 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) Scene_plane_item.cpp Scene_polygon_soup.cpp Scene_polyhedron_item.cpp + Scene_edit_polyhedron_item.cpp Scene_textured_polyhedron_item.cpp Scene_c2t3_item.cpp Scene_nef_polyhedron_item.cpp @@ -153,6 +154,10 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) Scene_polyhedron_item.cpp Scene_polyhedron_item.moc) target_link_libraries(scene_polyhedron_item demo_framework) + add_library(scene_edit_polyhedron_item SHARED + Scene_edit_polyhedron_item.cpp Scene_edit_polyhedron_item.moc) + target_link_libraries(scene_edit_polyhedron_item demo_framework) + if(TAUCS_FOUND) add_library(scene_textured_polyhedron_item SHARED Scene_textured_polyhedron_item.cpp texture.cpp Scene_textured_polyhedron_item.moc) @@ -311,6 +316,9 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) polyhedron_demo_plugin(trivial_plugin Polyhedron_demo_trivial_plugin) + polyhedron_demo_plugin(edit_polyhedron_plugin Polyhedron_demo_edit_polyhedron_plugin) + target_link_libraries(edit_polyhedron_plugin scene_polyhedron_item scene_edit_polyhedron_item) + polyhedron_demo_plugin(cut_plugin Polyhedron_demo_cut_plugin) target_link_libraries(cut_plugin scene_polyhedron_item scene_basic_objects) diff --git a/Polyhedron/demo/Polyhedron/MainWindow.cpp b/Polyhedron/demo/Polyhedron/MainWindow.cpp index a63d0e00fc4..45c2ddf3c31 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.cpp +++ b/Polyhedron/demo/Polyhedron/MainWindow.cpp @@ -157,6 +157,9 @@ MainWindow::MainWindow(QWidget* parent) connect(scene, SIGNAL(updated()), viewer, SLOT(update())); + connect(scene, SIGNAL(updated()), + this, SLOT(selectionChanged())); + connect(scene, SIGNAL(itemAboutToBeDestroyed(Scene_item*)), this, SLOT(removeManipulatedFrame(Scene_item*))); @@ -742,10 +745,26 @@ void MainWindow::selectionChanged() Scene_item* item = scene->item(getSelectedSceneItemIndex()); if(item != NULL && item->manipulatable()) { viewer->setManipulatedFrame(item->manipulatedFrame()); + } else { + viewer->setManipulatedFrame(0); + } + if(viewer->manipulatedFrame() == 0) { + Q_FOREACH(Scene_item* item, scene->entries()) { + if(item->manipulatable() && item->manipulatedFrame() != 0) { + if(viewer->manipulatedFrame() != 0) { + // there are at least two possible frames + viewer->setManipulatedFrame(0); + break; + } else { + viewer->setManipulatedFrame(item->manipulatedFrame()); + } + } + } + } + if(viewer->manipulatedFrame() != 0) { connect(viewer->manipulatedFrame(), SIGNAL(modified()), this, SLOT(updateInfo())); } - viewer->updateGL(); } diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_edit_polyhedron_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_edit_polyhedron_plugin.cpp new file mode 100644 index 00000000000..9d3421bf7ee --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_edit_polyhedron_plugin.cpp @@ -0,0 +1,118 @@ +#include "Scene_polyhedron_item.h" +#include "Scene_edit_polyhedron_item.h" +#include +#include +#include +#include + +#include "Polyhedron_demo_plugin_helper.h" + +class Polyhedron_demo_edit_polyhedron_plugin : + public QObject, + public Polyhedron_demo_plugin_helper +{ + Q_OBJECT + Q_INTERFACES(Polyhedron_demo_plugin_interface) + +public: + Polyhedron_demo_edit_polyhedron_plugin() + : Polyhedron_demo_plugin_helper(), size(0) + {} + + void init(QMainWindow* mainWindow, Scene_interface* scene_interface); + QList actions() const { + return QList() << actionToggleEdit; + } + +public slots: + void on_actionToggleEdit_triggered(); + void edition(); + +private: + QAction* actionToggleEdit; + int size; +}; // end Polyhedron_demo_edit_polyhedron_plugin + +void Polyhedron_demo_edit_polyhedron_plugin::init(QMainWindow* mainWindow, + Scene_interface* scene_interface) +{ + actionToggleEdit = new QAction(tr("Toggle &edition of item(s)"), mainWindow); + actionToggleEdit->setObjectName("actionToggleEdit"); + Polyhedron_demo_plugin_helper::init(mainWindow, scene_interface); +} + +void Polyhedron_demo_edit_polyhedron_plugin::on_actionToggleEdit_triggered() { + bool found_polyhedron = false; + bool edit_needed = false; + QList changed_items; + Q_FOREACH(Scene_interface::Item_id i, scene->selectionIndices()) + { + if(Scene_polyhedron_item* poly_item = + qobject_cast(scene->item(i))) + { + found_polyhedron = true; + Scene_edit_polyhedron_item* edit_poly = + new Scene_edit_polyhedron_item(poly_item); + edit_poly->setColor(poly_item->color()); + edit_poly->setName(QString("%1 (edit)").arg(poly_item->name())); + scene->replaceItem(i, edit_poly); + changed_items.push_back(scene->item(i)); + edit_needed = true; + connect(edit_poly, SIGNAL(modified()), + this, SLOT(edition())); + } else if(Scene_edit_polyhedron_item* poly_item = + qobject_cast(scene->item(i))) + { + found_polyhedron = true; + scene->replaceItem(i, poly_item->to_polyhedron_item()); + delete poly_item; + } + } + if(found_polyhedron == false) { + QMessageBox::warning(mw, tr("Warning"), + tr("No polyhedron was selected")); + } + if(edit_needed) { + size = QInputDialog::getInt(mw, + tr("Polyhedron edition zone"), + tr("Size of edition zone:"), + size /* default value */ , + 0 /* min */ ); + std::cerr << "size = " << size << std::endl; + Q_FOREACH(Scene_item* item, changed_items) + { + Scene_edit_polyhedron_item* poly_edit_item = + qobject_cast(item); + if(poly_edit_item) poly_edit_item->setZoneSize(size); + } + } +} + +void Polyhedron_demo_edit_polyhedron_plugin::edition() { + QObject* obj = sender(); + Scene_edit_polyhedron_item* edit_item = + qobject_cast(obj); + if(!edit_item) { + std::cerr << "ERROR" << __FILE__ << ":" << __LINE__ + << " : " << "unknown object type" << std::endl; + return; + } + + typedef Kernel::Point_3 Point; + typedef Kernel::Vector_3 Vector; + typedef Polyhedron::Vertex_handle Vertex_handle; + + const Point& orig = edit_item->original_position(); + const Vector move_vector = edit_item->current_position() - orig; + + Q_FOREACH(Vertex_handle vh, edit_item->selected_vertices()) + { + vh->point() = vh->point() + move_vector; + } + edit_item->changed(); // that reset the original_position() + scene->itemChanged(edit_item); +} + +Q_EXPORT_PLUGIN2(Polyhedron_demo_edit_polyhedron_plugin, Polyhedron_demo_edit_polyhedron_plugin) + +#include "Polyhedron_demo_edit_polyhedron_plugin.moc" diff --git a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp new file mode 100644 index 00000000000..4fb6ec0deb5 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp @@ -0,0 +1,239 @@ +#include "Scene_edit_polyhedron_item.h" +#include "Kernel_type.h" +#include "Polyhedron_type.h" + +#include + +#include +#include + +#include +#include +#include +#include + +#include + +typedef Polyhedron::Vertex_handle Vertex_handle; +typedef std::set Selected_vertices; +typedef Selected_vertices::iterator Selected_vertices_it; + +struct Scene_edit_polyhedron_item_priv { + Scene_polyhedron_item* poly_item; + int zone_size; + qglviewer::ManipulatedFrame* frame; + Selected_vertices selected_vertices; + Vertex_handle selected_vertex; + Kernel::Point_3 orig_pos; +}; // end struct Scene_edit_polyhedron_item_priv + +Scene_edit_polyhedron_item::Scene_edit_polyhedron_item(Scene_polyhedron_item* poly_item) + : d(new Scene_edit_polyhedron_item_priv) +{ + d->poly_item = poly_item; + d->zone_size = 0; + d->frame = new ManipulatedFrame(); + d->frame->setProperty("item", QVariant::fromValue(this)); + if(!connect(poly_item, SIGNAL(selected_vertex(void*)), + this, SLOT(vertex_has_been_selected(void*)))) + std::cerr << __FILE__ << ": connection failed!\n"; + poly_item->enable_facets_picking(true); +} + +Scene_edit_polyhedron_item::~Scene_edit_polyhedron_item() +{ + delete d->frame; + delete d; +} + +Scene_edit_polyhedron_item* +Scene_edit_polyhedron_item::clone() const { + return 0; +} + +QString +Scene_edit_polyhedron_item::toolTip() const +{ + if(!d->poly_item->polyhedron()) + return QString(); + + return QObject::tr("

Polyhedron %1 (mode: %5, color: %6)

" + "

Number of vertices: %2
" + "Number of edges: %3
" + "Number of facets: %4

") + .arg(this->name()) + .arg(d->poly_item->polyhedron()->size_of_vertices()) + .arg(d->poly_item->polyhedron()->size_of_halfedges()/2) + .arg(d->poly_item->polyhedron()->size_of_facets()) + .arg(this->renderingModeName()) + .arg(this->color().name()); +} + +#include "opengl_tools.h" + +void Scene_edit_polyhedron_item::draw() const { + d->poly_item->direct_draw(); + if(!d->selected_vertices.empty()) { + CGAL::GL::Point_size point_size; point_size.set_point_size(5); + CGAL::GL::Color color; color.set_rgb_color(0, 0, 0); + ::glBegin(GL_POINTS); + for(Selected_vertices_it + it = d->selected_vertices.begin(), + end = d->selected_vertices.end(); + it != end; ++it) + { + const Kernel::Point_3& p = (*it)->point(); + ::glVertex3d(p.x(), p.y(), p.z()); + } + ::glEnd(); + } +} + +Polyhedron* +Scene_edit_polyhedron_item::polyhedron() { return d->poly_item->polyhedron(); } +const Polyhedron* +Scene_edit_polyhedron_item::polyhedron() const { return d->poly_item->polyhedron(); } + +bool +Scene_edit_polyhedron_item::isEmpty() const { + return d->poly_item->isEmpty(); +} + +Scene_edit_polyhedron_item::Bbox +Scene_edit_polyhedron_item::bbox() const { + return d->poly_item->bbox(); +} + + +void +Scene_edit_polyhedron_item:: +changed() +{ + d->poly_item->changed(); + Scene_item::changed(); + d->orig_pos = current_position(); +} + +void +Scene_edit_polyhedron_item::select(double orig_x, + double orig_y, + double orig_z, + double dir_x, + double dir_y, + double dir_z) +{ + Scene_item::select(orig_x, + orig_y, + orig_z, + dir_x, + dir_y, + dir_z); + d->poly_item->select(orig_x, + orig_y, + orig_z, + dir_x, + dir_y, + dir_z); +} + +Scene_polyhedron_item* Scene_edit_polyhedron_item::to_polyhedron_item() const { + return d->poly_item; +} + +void +Scene_edit_polyhedron_item::setZoneSize(int i) { + if(i >= 0) { + std::cerr << "item \"" << qPrintable(name()) + << "\".setZoneSize(" << i << ")\n"; + d->zone_size = i; + } +} + +qglviewer::ManipulatedFrame* +Scene_edit_polyhedron_item::manipulatedFrame() { + return d->frame; +} + +struct Get_vertex_handle : public CGAL::Modifier_base +{ + Polyhedron::Vertex* vertex_ptr; + Vertex_handle vh; + void operator()(Polyhedron::HDS& hds) { + vh = hds.vertex_handle(vertex_ptr); + } +}; + +void Scene_edit_polyhedron_item::vertex_has_been_selected(void* void_ptr) { + Polyhedron* poly = d->poly_item->polyhedron(); + + // Need a modifier to get access to the HDS, to get the vertex handle + // from the vertex pointer. + + Get_vertex_handle get_vertex_handle; + get_vertex_handle.vertex_ptr = static_cast(void_ptr); + + poly->delegate(get_vertex_handle); + Vertex_handle vh = get_vertex_handle.vh; + + std::cerr << "Selected vertex: " << void_ptr << " = " << vh->point() + << std::endl; + d->selected_vertices.clear(); + + d->selected_vertices.insert(vh); + + std::cerr << "d->zone_size = " << d->zone_size << std::endl; + // Naive way to compute the k-neighborhood of vh, with k==d->zone_size. + for(int i = 0; i < d->zone_size; ++i) { + std::set selected_vertices; + for(Selected_vertices_it + it = d->selected_vertices.begin(), + end = d->selected_vertices.end(); + it != end; ++it) { + selected_vertices.insert(*it); + } + BOOST_FOREACH(Vertex_handle v, selected_vertices) { + Polyhedron::Halfedge_around_vertex_circulator + he_it = v->vertex_begin(), he_it_end(he_it); + if(he_it != 0) { + do { + const Vertex_handle other_v = he_it->opposite()->vertex(); + if( d->selected_vertices.find(other_v) == d->selected_vertices.end() ) + { + d->selected_vertices.insert(other_v); + } + } while(++he_it != he_it_end); + } + } + } + const Kernel::Point_3& p = vh->point(); + d->orig_pos = p; + d->frame->setPosition(qglviewer::Vec(p.x(), p.y(), p.z())); + connect(d->frame, SIGNAL(modified()), + this, SIGNAL(modified())); + emit begin_edit(); +} + +Vertex_handle +Scene_edit_polyhedron_item::selected_vertex() const { + return d->selected_vertex; +} + +QList +Scene_edit_polyhedron_item::selected_vertices() const { + QList result; + BOOST_FOREACH(Vertex_handle vh, d->selected_vertices) { + result << vh; + } + return result; +} + +Kernel::Point_3 Scene_edit_polyhedron_item::current_position() const { + const qglviewer::Vec vec = d->frame->position(); + return Kernel::Point_3(vec.x, vec.y, vec.z); +} + +Kernel::Point_3 Scene_edit_polyhedron_item::original_position() const { + return d->orig_pos; +} + +#include "Scene_edit_polyhedron_item.moc" diff --git a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h new file mode 100644 index 00000000000..a7d342493db --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h @@ -0,0 +1,89 @@ +#ifndef SCENE_EDIT_POLYHEDRON_ITEM_H +#define SCENE_EDIT_POLYHEDRON_ITEM_H + +#include "Scene_edit_polyhedron_item_config.h" +#include "Scene_polyhedron_item.h" +#include "Polyhedron_type.h" +#include + +#include + +#include +#include + +class QMenu; +struct Scene_edit_polyhedron_item_priv; + +// This class represents a polyhedron in the OpenGL scene +class SCENE_EDIT_POLYHEDRON_ITEM_EXPORT Scene_edit_polyhedron_item + : public Scene_item { + Q_OBJECT +public: + /// Create an Scene_edit_polyhedron_item from a Scene_polyhedron_item. + /// The ownership of the polyhedron is moved to the new edit_polyhedron + /// item. + Scene_edit_polyhedron_item(Scene_polyhedron_item* poly_item); + ~Scene_edit_polyhedron_item(); + + /// Returns 0, so that one cannot clone an "edit polyhedron" item. + Scene_edit_polyhedron_item* clone() const; + + // // IO + // bool load(std::istream& in); + // bool save(std::ostream& out) const; + + // Function for displaying meta-data of the item + QString toolTip() const; + + // // Function to override the context menu + // QMenu* contextMenu(); + + // Indicate if rendering mode is supported + bool supportsRenderingMode(RenderingMode) const { return true; } + // Points/Wireframe/Flat/Gouraud OpenGL drawing in a display list + void draw() const; + + bool manipulatable() const { return true; } + qglviewer::ManipulatedFrame* manipulatedFrame(); + + // Get wrapped polyhedron + Polyhedron* polyhedron(); + const Polyhedron* polyhedron() const; + + // Functions related to the edition + Kernel::Point_3 original_position() const; + Kernel::Point_3 current_position() const; + Polyhedron::Vertex_handle selected_vertex() const; + QList selected_vertices() const; + + /// Returns a Scene_polyhedron_item from the edit polyhedron item, and + /// transfer the ownership of the polyhedron to it. + /// The item 'this' must be destroy just after a call to this function. + Scene_polyhedron_item* to_polyhedron_item() const; + + // Get dimensions + bool isFinite() const { return true; } + bool isEmpty() const; + Bbox bbox() const; + +public slots: + void changed(); + void select(double orig_x, + double orig_y, + double orig_z, + double dir_x, + double dir_y, + double dir_z); + void setZoneSize(int i); + void vertex_has_been_selected(void* vertex_handle); + +signals: + void begin_edit(); + void modified(); + +protected: + Scene_edit_polyhedron_item_priv* d; + +}; // end class Scene_edit_polyhedron_item + +#endif // SCENE_EDIT_POLYHEDRON_ITEM_H diff --git a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item_config.h b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item_config.h new file mode 100644 index 00000000000..a1fde07abcf --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item_config.h @@ -0,0 +1,10 @@ +#ifndef SCENE_EDIT_POLYHEDRON_ITEM_CONFIG_H +#define SCENE_EDIT_POLYHEDRON_ITEM_CONFIG_H + +#ifdef scene_edit_polyhedron_item_EXPORTS +# define SCENE_EDIT_POLYHEDRON_ITEM_EXPORT Q_DECL_EXPORT +#else +# define SCENE_EDIT_POLYHEDRON_ITEM_EXPORT Q_DECL_IMPORT +#endif + +#endif // SCENE_EDIT_POLYHEDRON_ITEM_CONFIG_H diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp index 52a051f87bc..34bfb85fd94 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp @@ -348,16 +348,44 @@ Scene_polyhedron_item::select(double orig_x, } } if(closest_point) { - Polyhedron::Facet_handle selected_facet = closest->second; + Polyhedron::Facet_handle selected_fh = closest->second; + + // The computation of the nearest vertex may be costly. Only + // do it if some objects are connected to the signal + // 'selected_vertex'. + if(QObject::receivers(SIGNAL(selected_vertex(void*))) > 0) + { + Polyhedron::Halfedge_around_facet_circulator + he_it = selected_fh->facet_begin(), + around_end = he_it; + + Polyhedron::Vertex_handle v = he_it->vertex(), nearest_v = v; + + Kernel::FT sq_dist = CGAL::squared_distance(*closest_point, + v->point()); + + while(++he_it != around_end) { + v = he_it->vertex(); + Kernel::FT new_sq_dist = CGAL::squared_distance(*closest_point, + v->point()); + if(new_sq_dist < sq_dist) { + sq_dist = new_sq_dist; + nearest_v = v; + } + } + emit selected_vertex((void*)(&*nearest_v)); + } + + emit selected_facet((void*)(&*selected_fh)); if(erase_next_picked_facet_m) { - polyhedron()->erase_facet(selected_facet->halfedge()); + polyhedron()->erase_facet(selected_fh->halfedge()); polyhedron()->normalize_border(); set_erase_next_picked_facet(false); changed(); emit itemChanged(); } std::cerr << "Facet selected. patch_id=" - << selected_facet->patch_id() << std::endl; + << selected_fh->patch_id() << std::endl; } } } diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.h index 0342d290977..722c38b3ca1 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.h @@ -63,6 +63,11 @@ public slots: double dir_x, double dir_y, double dir_z); + +signals: + void selected_vertex(void*); + void selected_facet(void*); + private: // Initialization void init(); diff --git a/Polyhedron/demo/Polyhedron/opengl_tools.h b/Polyhedron/demo/Polyhedron/opengl_tools.h new file mode 100644 index 00000000000..2a5744f9262 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/opengl_tools.h @@ -0,0 +1,63 @@ +// Copyright (c) 2003 Utrecht University (The Netherlands), +// ETH Zurich (Switzerland), Freie Universitaet Berlin (Germany), +// INRIA Sophia-Antipolis (France), Martin-Luther-University Halle-Wittenberg +// (Germany), Max-Planck-Institute Saarbruecken (Germany), RISC Linz (Austria), +// and Tel-Aviv University (Israel). All rights reserved. +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; version 2.1 of the License. +// See the file LICENSE.LGPL distributed with CGAL. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Author(s) : Laurent Rineau + +#ifndef CGAL_OPENGL_TOOLS_H +#define CGAL_OPENGL_TOOLS_H + +#include + +namespace CGAL { +namespace GL { + +class Color { + GLfloat c[4]; +public: + Color() { + ::glGetFloatv(GL_COLOR, &c[0]); + } + ~Color() { + set_rgb_color(c[0], c[1], c[2], c[3]); + } + void set_rgb_color(GLfloat r, GLfloat g, GLfloat b, GLfloat a = 1.f) { + ::glColor4f(r, g, b, a); + } +}; // end class Color; + +class Point_size { + GLfloat ps; +public: + Point_size() { + ::glGetFloatv(GL_POINT_SIZE, &ps); + } + ~Point_size() { + set_point_size(ps); + } + void set_point_size(GLfloat v) { + ::glPointSize(v); + } +}; // end class Point_size + +} // end namespace GL +} // end namespace CGAL + +#endif // not CGAL_OPENGL_TOOLS_H