In Polyhedron demo, add possibility to modify a polyhedron, by picking,

dragging, modelling...

Merge of /branches/features/polyhedron-demo_polyhedron_modeling-lrineau
Tested in candidates in CGAL-3.9-Ic-41.
This commit is contained in:
Laurent Rineau 2011-06-09 13:15:31 +00:00
commit f180a09d55
9 changed files with 583 additions and 4 deletions

View File

@ -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)

View File

@ -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();
}

View File

@ -0,0 +1,118 @@
#include "Scene_polyhedron_item.h"
#include "Scene_edit_polyhedron_item.h"
#include <QAction>
#include <QMainWindow>
#include <QMessageBox>
#include <QInputDialog>
#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<QAction*> actions() const {
return QList<QAction*>() << 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<Scene_item*> changed_items;
Q_FOREACH(Scene_interface::Item_id i, scene->selectionIndices())
{
if(Scene_polyhedron_item* poly_item =
qobject_cast<Scene_polyhedron_item*>(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_edit_polyhedron_item*>(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<Scene_edit_polyhedron_item*>(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<Scene_edit_polyhedron_item*>(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"

View File

@ -0,0 +1,239 @@
#include "Scene_edit_polyhedron_item.h"
#include "Kernel_type.h"
#include "Polyhedron_type.h"
#include <boost/foreach.hpp>
#include <QVariant>
#include <set>
#include <QObject>
#include <QMenu>
#include <QAction>
#include <CGAL/gl_render.h>
#include <QGLViewer/manipulatedFrame.h>
typedef Polyhedron::Vertex_handle Vertex_handle;
typedef std::set<Vertex_handle> 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<QObject*>(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("<p>Polyhedron <b>%1</b> (mode: %5, color: %6)</p>"
"<p>Number of vertices: %2<br />"
"Number of edges: %3<br />"
"Number of facets: %4</p>")
.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::HDS>
{
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<Polyhedron::Vertex*>(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<Vertex_handle> 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<Vertex_handle>
Scene_edit_polyhedron_item::selected_vertices() const {
QList<Vertex_handle> 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"

View File

@ -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 <iostream>
#include <vector>
#include <QColor>
#include <QList>
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<Polyhedron::Vertex_handle> 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

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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();

View File

@ -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 <laurent.rineau__CGAL@normalesup.org>
#ifndef CGAL_OPENGL_TOOLS_H
#define CGAL_OPENGL_TOOLS_H
#include <CGAL/gl.h>
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