Merge branch 'gsoc2011-surface-modeling-Yzju' into Surface_modeling-new_package-GF

Conflicts:
	.gitattributes
	AABB_tree/doc_tex/AABB_tree_ref/AABBGeomTraits.tex
	AABB_tree/doc_tex/AABB_tree_ref/AABBTraits.tex
	AABB_tree/dont_submit
	AABB_tree/test/AABB_tree/AABB_test_util.h
	AABB_tree/test/AABB_tree/aabb_correctness_triangle_test.cpp
	Arrangement_on_surface_2/include/CGAL/Arr_point_location/Trapezoidal_decomposition_2_impl.h
	Boolean_set_operations_2/examples/Boolean_set_operations_2/bezier_traits_adapter2.cpp
	Installation/cmake/modules/CGAL_CreateSingleSourceCGALProgram.cmake
	Installation/cmake/modules/CGAL_Macros.cmake
	Installation/cmake/modules/CGAL_SetupDependencies.cmake
	Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_triangulation.cpp
	Maintenance/svn_server/hooks/Mail/Sender/CType/Ext.pm
	Polyhedron/demo/Polyhedron/CMakeLists.txt
	Polyhedron/demo/Polyhedron/Polyhedron_demo_normal_estimation_plugin.cpp
	Polyhedron/demo/Polyhedron/Polyhedron_demo_point_set_outliers_removal_plugin.cpp
	Polyhedron/demo/Polyhedron/data/cow.off
	Principal_component_analysis/test/Principal_component_analysis/linear_least_squares_fitting_segments_3.cpp
	Surface_mesh_parameterization/examples/Surface_mesh_parameterization/CMakeLists.txt
	Surface_reconstruction_points_3/include/CGAL/Poisson_reconstruction_function.h
This commit is contained in:
Sébastien Loriot 2013-02-07 17:00:00 +01:00
commit c8fb9844aa
29 changed files with 22730 additions and 103 deletions

View File

@ -0,0 +1,47 @@
# Umfpack lib usually requires linking to a blas library.
# It is up to the user of this module to find a BLAS and link to it.
find_package(LAPACK)
if (NOT LAPACK_FOUND)
message(STATUS "SuperLU requires LAPACK and BLAS that could not be found.")
set(SUPERLU_FOUND FALSE)
else()
if (SUPERLU_INCLUDES AND SUPERLU_LIBRARIES)
set(SUPERLU_FIND_QUIETLY TRUE)
endif (SUPERLU_INCLUDES AND SUPERLU_LIBRARIES)
find_path(SUPERLU_INCLUDES
NAMES
supermatrix.h
HINTS
$ENV{SUPERLUDIR}/SRC
$ENV{SUPERLU_INC_DIR}
PATHS
${INCLUDE_INSTALL_DIR}
PATH_SUFFIXES
superlu
SRC
)
find_library(SUPERLU_LIBRARIES superlu
HINTS
$ENV{SUPERLU_LIB_DIR}
$ENV{SUPERLUDIR}/lib
PATHS
${LIB_INSTALL_DIR}
PATH_SUFFIXES
lib
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(SUPERLU DEFAULT_MSG
SUPERLU_INCLUDES SUPERLU_LIBRARIES)
mark_as_advanced(SUPERLU_INCLUDES SUPERLU_LIBRARIES)
endif()
if(SUPERLU_FOUND)
set(SUPERLU_USE_FILE "UseSuperLU")
endif(SUPERLU_FOUND)

View File

@ -0,0 +1,28 @@
# This module setups the compiler for the SuperLU libraries.
# It assumes that find_package(SuperLU) was already called.
if ( SUPERLU_FOUND AND NOT CGAL_SUPERLU_SETUP )
message( STATUS "SuperLU include: ${SUPERLU_INCLUDES}" )
include_directories ( ${SUPERLU_INCLUDES} )
message( STATUS "SuperLU definitions: ${SUPERLU_DEFINITIONS}" )
add_definitions( ${SUPERLU_DEFINITIONS} "-DCGAL_SUPERLU_ENABLED" )
if (SUPERLU_LIBRARIES_DIR)
message( STATUS "SuperLU library directories: ${SUPERLU_LIBRARIES_DIR}" )
link_directories( ${SUPERLU_LIBRARIES_DIR} )
endif()
if (SUPERLU_LIBRARIES)
message( STATUS "SuperLU libraries: ${SUPERLU_LIBRARIES}" )
link_libraries( ${SUPERLU_LIBRARIES} )
endif()
# SuperLU requires BLAS and LAPACK
include( ${LAPACK_USE_FILE} )
# Setup is done
set ( CGAL_SUPERLU_SETUP TRUE )
endif()

View File

@ -91,6 +91,15 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND)
if(NOT EIGEN3_FOUND AND NOT TAUCS_FOUND) if(NOT EIGEN3_FOUND AND NOT TAUCS_FOUND)
message(STATUS "NOTICE: Eigen 3.1 (or greater) and TAUCS is not found. parametrization will not be available.") message(STATUS "NOTICE: Eigen 3.1 (or greater) and TAUCS is not found. parametrization will not be available.")
endif(NOT EIGEN3_FOUND AND NOT TAUCS_FOUND) endif(NOT EIGEN3_FOUND AND NOT TAUCS_FOUND)
if(EIGEN3_FOUND)
find_package(SuperLU)
if(SUPERLU_FOUND)
include( ${SUPERLU_USE_FILE} )
else()
message(STATUS "NOTICE: SuperLU is not found, Surface deformation plugin will not be available.")
endif()
endif()
# Curvature estimation needs Eigen3 or LAPACK # Curvature estimation needs Eigen3 or LAPACK
if(NOT EIGEN3_FOUND AND NOT LAPACK_FOUND) if(NOT EIGEN3_FOUND AND NOT LAPACK_FOUND)
@ -104,6 +113,7 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND)
qt4_wrap_ui( meshingUI_FILES Meshing_dialog.ui Meshing_pause_widget.ui ) qt4_wrap_ui( meshingUI_FILES Meshing_dialog.ui Meshing_pause_widget.ui )
qt4_wrap_ui( cameraUI_FILES Camera_positions_list.ui ) qt4_wrap_ui( cameraUI_FILES Camera_positions_list.ui )
qt4_wrap_ui( PreferencesUI_FILES Preferences.ui ) qt4_wrap_ui( PreferencesUI_FILES Preferences.ui )
qt4_wrap_ui( editionUI_FILES Deform_mesh.ui )
qt4_wrap_ui( funcUI_FILES Function_dialog.ui ) qt4_wrap_ui( funcUI_FILES Function_dialog.ui )
@ -394,8 +404,10 @@ 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(trivial_plugin Polyhedron_demo_trivial_plugin)
polyhedron_demo_plugin(edit_polyhedron_plugin Polyhedron_demo_edit_polyhedron_plugin) if(TAUCS_FOUND OR ( EIGEN3_FOUND AND SUPERLU_FOUND ) )
target_link_libraries(edit_polyhedron_plugin scene_polyhedron_item scene_edit_polyhedron_item) polyhedron_demo_plugin(edit_polyhedron_plugin Polyhedron_demo_edit_polyhedron_plugin ${editionUI_FILES})
target_link_libraries(edit_polyhedron_plugin scene_polyhedron_item scene_edit_polyhedron_item)
endif()
polyhedron_demo_plugin(cut_plugin Polyhedron_demo_cut_plugin) polyhedron_demo_plugin(cut_plugin Polyhedron_demo_cut_plugin)
target_link_libraries(cut_plugin scene_polyhedron_item scene_basic_objects) target_link_libraries(cut_plugin scene_polyhedron_item scene_basic_objects)

View File

@ -0,0 +1,151 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DeformMesh</class>
<widget class="QDockWidget" name="DeformMesh">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>286</width>
<height>257</height>
</rect>
</property>
<property name="windowTitle">
<string>Polyhedron &amp;deformation</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="editModeCb">
<property name="text">
<string>&amp;Edit mode</string>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="title">
<string>Edition region</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="1">
<widget class="QSpinBox" name="interestRegionSize">
<property name="maximum">
<number>999999999</number>
</property>
<property name="value">
<number>6</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>&amp;Interest region size</string>
</property>
<property name="buddy">
<cstring>interestRegionSize</cstring>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QPushButton" name="startDeformPb">
<property name="text">
<string>Start deform</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QPushButton" name="clearHandlesPb">
<property name="text">
<string>Clear handles</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>&amp;Handles region size</string>
</property>
<property name="buddy">
<cstring>handlesRegionSize</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="handlesRegionSize">
<property name="maximum">
<number>999999999</number>
</property>
<property name="value">
<number>2</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="geodesicCircleCb">
<property name="text">
<string>Geodesic circle</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="usageScenarioCb">
<item>
<property name="text">
<string>single handle</string>
</property>
</item>
<item>
<property name="text">
<string>multiple handle</string>
</property>
</item>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Usage scenario</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="sharpFeatureCb">
<property name="text">
<string>Sharp feature</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>editModeCb</sender>
<signal>toggled(bool)</signal>
<receiver>groupBox</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>65</x>
<y>40</y>
</hint>
<hint type="destinationlabel">
<x>72</x>
<y>58</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -1,11 +1,58 @@
#define CGAL_DEFORM_ROTATION
#ifdef CGAL_EIGEN3_ENABLED
#include <CGAL/Eigen_solver_traits.h>
#ifdef CGAL_SUPERLU_ENABLED
#include <Eigen/SuperLUSupport>
#endif
#endif
#include "Polyhedron_demo_plugin_helper.h"
#include "Scene_polyhedron_item.h" #include "Scene_polyhedron_item.h"
#include "Scene_edit_polyhedron_item.h" #include "Scene_edit_polyhedron_item.h"
#include <QAction> #include <QAction>
#include <QKeySequence>
#include <QMainWindow> #include <QMainWindow>
#include <QMessageBox> #include <QMessageBox>
#include <QInputDialog> #include <QInputDialog>
#include <QSettings>
#include "Polyhedron_demo_plugin_helper.h" #include <QGLViewer/qglviewer.h>
#include <QDockWidget>
#include "ui_Deform_mesh.h"
#include "Property_maps_for_edit_plugin.h"
#include <CGAL/Deform_mesh.h>
typedef Polyhedron_vertex_deformation_index_map<Polyhedron> Vertex_index_map;
typedef Polyhedron_edge_deformation_index_map<Polyhedron> Edge_index_map;
#if defined(CGAL_EIGEN3_ENABLED) && defined(CGAL_SUPERLU_ENABLED)
typedef CGAL::Eigen_solver_traits<Eigen::SuperLU<CGAL::Eigen_sparse_matrix<double>::EigenType> > DefaultSolver;
#elif defined(CGAL_TAUCS_ENABLED)
#include <CGAL/Taucs_solver_traits.h>
typedef CGAL::Taucs_solver_traits<double> DefaultSolver;
#else
typedef CGAL::Eigen_solver_traits<Eigen::BiCGSTAB<CGAL::Eigen_sparse_matrix<double>::EigenType> > DefaultSolver;
#endif
typedef CGAL::Deform_mesh<Polyhedron, DefaultSolver, Vertex_index_map, Edge_index_map> Deform_mesh;
typedef Kernel::Point_3 Point;
typedef Kernel::Vector_3 Vector;
typedef Polyhedron::Vertex_handle Vertex_handle;
struct Polyhedron_deformation_data {
Deform_mesh* deform_mesh;
bool preprocessed; // specify whether preprocessed or not
std::map<Vertex_handle, Vector> handle_vectors; // record transform vectors of all handles,
// only for multiple handle region scenario
};
class Polyhedron_demo_edit_polyhedron_plugin : class Polyhedron_demo_edit_polyhedron_plugin :
public QObject, public QObject,
@ -16,10 +63,13 @@ class Polyhedron_demo_edit_polyhedron_plugin :
public: public:
Polyhedron_demo_edit_polyhedron_plugin() Polyhedron_demo_edit_polyhedron_plugin()
: Polyhedron_demo_plugin_helper(), size(0) : Polyhedron_demo_plugin_helper(), size(0), edit_mode(false)
{} {}
~Polyhedron_demo_edit_polyhedron_plugin();
void init(QMainWindow* mainWindow, Scene_interface* scene_interface); void init(QMainWindow* mainWindow, Scene_interface* scene_interface);
QList<QAction*> actions() const { QList<QAction*> actions() const {
return QList<QAction*>() << actionToggleEdit; return QList<QAction*>() << actionToggleEdit;
} }
@ -35,69 +85,442 @@ public:
return false; return false;
} }
public slots: public slots:
void on_actionToggleEdit_triggered(); void on_actionToggleEdit_triggered(bool);
void start_deform();
void clear_handles();
void preprocess(Scene_edit_polyhedron_item* edit_item);
void complete_deform(Scene_edit_polyhedron_item* edit_item);
void edition(); void edition();
void usage_scenario_0(Scene_edit_polyhedron_item* edit_item);
void usage_scenario_1(Scene_edit_polyhedron_item* edit_item);
void item_destroyed();
void new_item_created(int item_id);
void update_handlesRegionSize(int interestRegionSizeValue) {
if(deform_mesh_widget.handlesRegionSize->value() > interestRegionSizeValue)
{
deform_mesh_widget.handlesRegionSize->setValue(interestRegionSizeValue);
}
}
void update_interestRegionSize(int handlesRegionSizeValue) {
if(deform_mesh_widget.interestRegionSize->value() < handlesRegionSizeValue)
{
deform_mesh_widget.interestRegionSize->setValue(handlesRegionSizeValue);
}
}
private: private:
typedef Scene_interface::Item_id Item_id;
Scene_edit_polyhedron_item*
convert_to_edit_polyhedron(Item_id, Scene_polyhedron_item*);
Scene_polyhedron_item*
convert_to_plain_polyhedron(Item_id, Scene_edit_polyhedron_item*);
typedef std::map<QObject*, Polyhedron_deformation_data> Deform_map;
Deform_map deform_map;
Ui::DeformMesh deform_mesh_widget;
QDockWidget* widget;
QAction* actionToggleEdit; QAction* actionToggleEdit;
int size; int size;
bool edit_mode;
}; // end Polyhedron_demo_edit_polyhedron_plugin }; // end Polyhedron_demo_edit_polyhedron_plugin
Polyhedron_demo_edit_polyhedron_plugin::
~Polyhedron_demo_edit_polyhedron_plugin()
{
QSettings settings;
settings.beginGroup("Polyhedron edition");
settings.setValue("Deform_mesh widget area",
this->mw->dockWidgetArea(widget));
settings.endGroup();
}
void Polyhedron_demo_edit_polyhedron_plugin::init(QMainWindow* mainWindow, void Polyhedron_demo_edit_polyhedron_plugin::init(QMainWindow* mainWindow,
Scene_interface* scene_interface) Scene_interface* scene_interface)
{ {
actionToggleEdit = new QAction(tr("Toggle &edition of item(s)"), mainWindow); actionToggleEdit = new QAction(tr("Toggle &edition of item(s)"), mainWindow);
actionToggleEdit->setObjectName("actionToggleEdit"); actionToggleEdit->setObjectName("actionToggleEdit");
actionToggleEdit->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E));
actionToggleEdit->setCheckable(true);
QSettings settings;
settings.beginGroup("Polyhedron edition");
int i = settings.value("Deform_mesh widget area",
Qt::LeftDockWidgetArea).toInt();
Qt::DockWidgetArea area = static_cast<Qt::DockWidgetArea>(i);
settings.endGroup();
widget = new QDockWidget();
deform_mesh_widget.setupUi(widget);
mainWindow->addDockWidget(area, widget);
// bind states of actionToggleEdit and editModeCb
connect(actionToggleEdit, SIGNAL(triggered(bool)),
deform_mesh_widget.editModeCb, SLOT(setChecked(bool)));
connect(deform_mesh_widget.editModeCb, SIGNAL(clicked(bool)),
actionToggleEdit, SLOT(setChecked(bool)));
// make editModeCb actually trigger the slot
connect(deform_mesh_widget.editModeCb, SIGNAL(clicked(bool)),
this, SLOT(on_actionToggleEdit_triggered(bool)));
// Connect Scene::newItem so that, if edit_mode==true, convert
// automatically polyhedron items to "edit polyhedron" items.
QObject* scene = dynamic_cast<QObject*>(scene_interface);
if(scene) {
connect(scene, SIGNAL(newItem(int)),
this, SLOT(new_item_created(int)));
} else {
std::cerr << "ERROR " << __FILE__ << ":" << __LINE__ << " :"
<< " cannot convert scene_interface to scene!\n";
}
// Make sure handlesRegionSize->value() is always smaller than
// interestRegionSize->value()
connect(deform_mesh_widget.handlesRegionSize, SIGNAL(valueChanged(int)),
this, SLOT(update_interestRegionSize(int)));
connect(deform_mesh_widget.interestRegionSize, SIGNAL(valueChanged(int)),
this, SLOT(update_handlesRegionSize(int)));
connect(deform_mesh_widget.startDeformPb, SIGNAL(clicked(bool)),
this, SLOT(start_deform()));
connect(deform_mesh_widget.clearHandlesPb, SIGNAL(clicked(bool)),
this, SLOT(clear_handles()));
connect(deform_mesh_widget.usageScenarioCb, SIGNAL(currentIndexChanged(int)),
this, SLOT(clear_handles()));
Polyhedron_demo_plugin_helper::init(mainWindow, scene_interface); Polyhedron_demo_plugin_helper::init(mainWindow, scene_interface);
} }
void Polyhedron_demo_edit_polyhedron_plugin::on_actionToggleEdit_triggered() { void
bool found_polyhedron = false; Polyhedron_demo_edit_polyhedron_plugin::new_item_created(int item_id)
bool edit_needed = false; {
QList<Scene_item*> changed_items; if(edit_mode) {
Q_FOREACH(Scene_interface::Item_id i, scene->selectionIndices()) Scene_polyhedron_item* poly_item =
{ qobject_cast<Scene_polyhedron_item*>(scene->item(item_id));
if(Scene_polyhedron_item* poly_item = if(poly_item) {
qobject_cast<Scene_polyhedron_item*>(scene->item(i))) convert_to_edit_polyhedron(item_id, poly_item);
{
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);
} }
} }
} }
Scene_edit_polyhedron_item*
Polyhedron_demo_edit_polyhedron_plugin::
convert_to_edit_polyhedron(Item_id i,
Scene_polyhedron_item* poly_item)
{
QString poly_item_name = poly_item->name();
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()));
poly_item->setName(poly_item_name); // Because it is changed when the
// name of edit_poly is changed.
edit_poly->setVisible(poly_item->visible());
edit_poly->setHandlesRegionSize(deform_mesh_widget.handlesRegionSize->value());
edit_poly->setInterestRegionSize(deform_mesh_widget.interestRegionSize->value());
edit_poly->setGeodesicCircle(deform_mesh_widget.geodesicCircleCb->isChecked());
edit_poly->setSharpFeature(deform_mesh_widget.sharpFeatureCb->isChecked());
edit_poly->setUsageScenario(deform_mesh_widget.usageScenarioCb->currentIndex());
edit_poly->setSelectedHandlesMoved(false);
edit_poly->setSelectedVertexChanged(false);
connect(edit_poly, SIGNAL(modified()),
this, SLOT(edition()));
connect(edit_poly, SIGNAL(destroyed()),
this, SLOT(item_destroyed()));
connect(deform_mesh_widget.handlesRegionSize, SIGNAL(valueChanged(int)),
edit_poly, SLOT(setHandlesRegionSize(int)));
connect(deform_mesh_widget.interestRegionSize, SIGNAL(valueChanged(int)),
edit_poly, SLOT(setInterestRegionSize(int)));
connect(deform_mesh_widget.geodesicCircleCb, SIGNAL(clicked(bool)),
edit_poly, SLOT(setGeodesicCircle(bool)));
connect(deform_mesh_widget.sharpFeatureCb, SIGNAL(clicked(bool)),
edit_poly, SLOT(setSharpFeature(bool)));
connect(deform_mesh_widget.usageScenarioCb, SIGNAL(currentIndexChanged(int)),
edit_poly, SLOT(setUsageScenario(int)));
scene->replaceItem(i, edit_poly);
return edit_poly;
}
Scene_polyhedron_item*
Polyhedron_demo_edit_polyhedron_plugin::
convert_to_plain_polyhedron(Item_id i,
Scene_edit_polyhedron_item* edit_item)
{
Scene_polyhedron_item* poly_item = edit_item->to_polyhedron_item();
scene->replaceItem(i, poly_item);
delete edit_item;
return poly_item;
}
void Polyhedron_demo_edit_polyhedron_plugin::on_actionToggleEdit_triggered(bool edit) {
this->edit_mode = edit;
for(Scene_interface::Item_id i = 0, end = scene->numberOfEntries();
i < end; ++i)
{
Scene_polyhedron_item* poly_item =
qobject_cast<Scene_polyhedron_item*>(scene->item(i));
if (poly_item) poly_item->update_halfedge_indices();
Scene_edit_polyhedron_item* edit_item =
qobject_cast<Scene_edit_polyhedron_item*>(scene->item(i));
if(edit && poly_item) {
convert_to_edit_polyhedron(i, poly_item);
} else if(!edit && edit_item) {
convert_to_plain_polyhedron(i, edit_item);
}
}
}
// Remove from 'deform_map' the metadata that corresponds to the deleted
// item.
void Polyhedron_demo_edit_polyhedron_plugin::item_destroyed() {
QObject* obj = sender(); // the item that is destroyed
Deform_map::iterator it = deform_map.find(obj);
if(it != deform_map.end()) {
delete it->second.deform_mesh; // TODO: uncomment that!
deform_map.erase(it);
}
}
// Clear all the existing handles and ROI and recover mesh to original one
void Polyhedron_demo_edit_polyhedron_plugin::clear_handles() {
int item_id = scene->mainSelectionIndex();
Scene_edit_polyhedron_item* edit_item =
qobject_cast<Scene_edit_polyhedron_item*>(scene->item(item_id));
if(!edit_item) return; // the selected item is not of the right type
Polyhedron* polyhedron = edit_item->polyhedron();
Deform_map::iterator deform_it = deform_map.find(edit_item);
if(deform_it != deform_map.end())
{
Polyhedron_deformation_data& data = deform_map[edit_item];
Deform_mesh* deform = data.deform_mesh;
deform->clear_handles();
deform->clear_roi();
data.preprocessed = false;
}
edit_item->clear_selected_handles();
edit_item->clear_non_selected_handles();
edit_item->clear_selected_roi();
edit_item->clear_non_selected_roi();
edit_item->clear_selected_vectors();
edit_item->clear_non_selected_vectors();
// signal to the item that it needs to recompute its internal structures
edit_item->changed(); // that reset the last_position()
// signal to the scene that the item needs to be redrawn.
scene->itemChanged(edit_item);
}
// Start deformation: preprocess or complete deformation
void Polyhedron_demo_edit_polyhedron_plugin::start_deform() {
int item_id = scene->mainSelectionIndex();
Scene_edit_polyhedron_item* edit_item =
qobject_cast<Scene_edit_polyhedron_item*>(scene->item(item_id));
if(!edit_item) return; // the selected item is not of the right type
// do deformation only when handles are selected
if (edit_item->selected_vertices().isEmpty()) return;
//if ( edit_item->usage_scenario() == 0 )
{
preprocess(edit_item);
}
/*else
{
complete_deform(edit_item);
}*/
}
// Pre-processing of deformation, adaptive with usage_scenario_1
void Polyhedron_demo_edit_polyhedron_plugin::preprocess(Scene_edit_polyhedron_item* edit_item) {
Polyhedron* polyhedron = edit_item->polyhedron();
Deform_map::iterator deform_it = deform_map.find(edit_item);
if(deform_it == deform_map.end()) // First time. Need to create the Deform_mesh object.
{
Polyhedron_deformation_data& new_data = deform_map[edit_item];
Deform_mesh* new_deform = new Deform_mesh(*polyhedron, Vertex_index_map(), Edge_index_map());
new_data.deform_mesh = new_deform;
new_data.preprocessed = false;
new_deform->clear_handles();
Q_FOREACH(Vertex_handle vh, edit_item->selected_handles())
new_deform->insert_handle(vh);
Q_FOREACH(Vertex_handle vh, edit_item->non_selected_handles())
new_deform->insert_handle(vh);
new_deform->clear_roi();
Q_FOREACH(Vertex_handle vh, edit_item->selected_roi())
new_deform->insert_roi(vh);
Q_FOREACH(Vertex_handle vh, edit_item->non_selected_roi())
new_deform->insert_roi(vh);
}
Polyhedron_deformation_data& data = deform_map[edit_item];
Deform_mesh* deform = data.deform_mesh;
// precomputation of Laplacian matrix
deform->preprocess();
data.preprocessed = true;
}
// Complete deformation, adaptive with usage_scenario_2
void Polyhedron_demo_edit_polyhedron_plugin::complete_deform(Scene_edit_polyhedron_item* edit_item) {
Polyhedron* polyhedron = edit_item->polyhedron();
Deform_map::iterator deform_it = deform_map.find(edit_item);
if(deform_it == deform_map.end()) return;
Polyhedron_deformation_data& data = deform_map[edit_item];
Deform_mesh* deform = data.deform_mesh;
// precomputation of Laplacian matrix
deform->preprocess();
data.preprocessed = true;
deform->deform();
// signal to the item that it needs to recompute its internal structures
edit_item->changed(); // that reset the last_position()
// signal to the scene that the item needs to be redrawn.
scene->itemChanged(edit_item);
}
// classic ROI + single handle paradigm
void Polyhedron_demo_edit_polyhedron_plugin::usage_scenario_0(Scene_edit_polyhedron_item* edit_item) {
Polyhedron* polyhedron = edit_item->polyhedron();
const Point& orig = edit_item->original_position();
const Vector translation_origin = edit_item->current_position() - orig;
const Point& last = edit_item->last_position();
const Vector translation_last = edit_item->current_position() - last;
Polyhedron_deformation_data& data = deform_map[edit_item];
Deform_mesh* deform = data.deform_mesh;
if ( translation_origin == Vector(0, 0, 0) && translation_last == Vector(0, 0, 0) ) // vertex selection: reset deform class
{
deform->clear_handles();
Q_FOREACH(Vertex_handle vh, edit_item->selected_handles())
deform->insert_handle(vh);
Q_FOREACH(Vertex_handle vh, edit_item->non_selected_handles())
deform->insert_handle(vh);
deform->clear_roi();
Q_FOREACH(Vertex_handle vh, edit_item->selected_roi())
deform->insert_roi(vh);
Q_FOREACH(Vertex_handle vh, edit_item->non_selected_roi())
deform->insert_roi(vh);
data.preprocessed = false;
}
else // moving frame: actual deformation
{
if ( !data.preprocessed ) // need preprocessing
{
// precomputation of Laplacian matrix
deform->preprocess();
data.preprocessed = true;
}
// -- ACTUAL DEFORMATION --
(*deform)(translation_origin);
deform->deform();
// -- END OF ACTUAL DEFORMATION --
}
}
// point-based multiple handle manipulation
void Polyhedron_demo_edit_polyhedron_plugin::usage_scenario_1(Scene_edit_polyhedron_item* edit_item) {
Polyhedron* polyhedron = edit_item->polyhedron();
const Point& orig = edit_item->original_position();
Point poi; // AF: This works only if we have a single ROI
const Vector translation_origin = edit_item->current_position() - orig;
const Point& last = edit_item->last_position();
const Vector translation_last = edit_item->current_position() - last;
Polyhedron_deformation_data& data = deform_map[edit_item];
Deform_mesh* deform = data.deform_mesh;
if ( translation_origin == Vector(0, 0, 0) && translation_last == Vector(0, 0, 0) ) // handle selection
{
std::cerr << "reset something" << std::endl;
deform->clear_handles();
Q_FOREACH(Vertex_handle vh, edit_item->selected_handles())
deform->insert_handle(vh);
Q_FOREACH(Vertex_handle vh, edit_item->non_selected_handles())
deform->insert_handle(vh);
deform->clear_roi();
Q_FOREACH(Vertex_handle vh, edit_item->selected_roi())
deform->insert_roi(vh);
Q_FOREACH(Vertex_handle vh, edit_item->non_selected_roi())
deform->insert_roi(vh);
data.preprocessed = false;
}
else // moving frame: move new handles
{
if ( !data.preprocessed )
{
edit_item->setSelectedVector(translation_last);
edit_item->setSelectedHandlesMoved(true);
Q_FOREACH(Vertex_handle vh, edit_item->selected_handles())
data.handle_vectors[vh] = translation_origin;
}
else
{
// AF: for the rotation+ translation, we have to translate handles by ORIGIN-poi
// make the rotation, translate back, and apply the additional translation.
Vector vec = edit_item->selected_vector().second - edit_item->selected_vector().first;
poi = edit_item->selected_vector().first;
double scalar = translation_origin*vec / vec.squared_length() /3.0;
if (scalar > 1) scalar = 1;
if (scalar < 0) scalar = 0;
std::map<Vertex_handle, Vector>::iterator it = data.handle_vectors.begin();
while ( it != data.handle_vectors.end() ) // apply scalar factor to each handle region
{
qglviewer::Quaternion quat(qglviewer::Vec(scalar * it->second.x(),
scalar * it->second.y(),
scalar * it->second.z()), scalar * 3.14);
qglviewer::Vec disp(scalar * it->second.x(), scalar * it->second.y(), scalar * it->second.z());
(*deform)( it->first, poi, quat, disp);// 0 for the match
// (*deform)( it->first, scalar*(it->second) );
it++;
}
deform->deform();
}
}
}
void Polyhedron_demo_edit_polyhedron_plugin::edition() { void Polyhedron_demo_edit_polyhedron_plugin::edition() {
QObject* obj = sender(); QObject* obj = sender();
Scene_edit_polyhedron_item* edit_item = Scene_edit_polyhedron_item* edit_item =
@ -108,18 +531,43 @@ void Polyhedron_demo_edit_polyhedron_plugin::edition() {
return; return;
} }
typedef Kernel::Point_3 Point; // do deformation only when handles are selected
typedef Kernel::Vector_3 Vector; if (edit_item->selected_vertices().isEmpty()) return;
typedef Polyhedron::Vertex_handle Vertex_handle;
const Point& orig = edit_item->original_position(); Polyhedron* polyhedron = edit_item->polyhedron();
const Vector move_vector = edit_item->current_position() - orig; Deform_map::iterator deform_it = deform_map.find(edit_item);
if(deform_it == deform_map.end()) // First time. Need to create the Deform_mesh object.
Q_FOREACH(Vertex_handle vh, edit_item->selected_vertices())
{ {
vh->point() = vh->point() + move_vector; Polyhedron_deformation_data& new_data = deform_map[edit_item];
Deform_mesh* new_deform = new Deform_mesh(*polyhedron, Vertex_index_map(), Edge_index_map());
new_data.deform_mesh = new_deform;
new_data.preprocessed = false;
new_deform->clear_handles();
Q_FOREACH(Vertex_handle vh, edit_item->selected_handles())
new_deform->insert_handle(vh);
Q_FOREACH(Vertex_handle vh, edit_item->non_selected_handles())
new_deform->insert_handle(vh);
new_deform->clear_roi();
Q_FOREACH(Vertex_handle vh, edit_item->selected_roi())
new_deform->insert_roi(vh);
Q_FOREACH(Vertex_handle vh, edit_item->non_selected_roi())
new_deform->insert_roi(vh);
} }
edit_item->changed(); // that reset the original_position()
if ( edit_item->usage_scenario() == 0 )
{
usage_scenario_0(edit_item);
}
else
{
usage_scenario_1(edit_item);
}
// signal to the item that it needs to recompute its internal structures
edit_item->changed(); // that reset the last_position()
// signal to the scene that the item needs to be redrawn.
scene->itemChanged(edit_item); scene->itemChanged(edit_item);
} }

View File

@ -0,0 +1,120 @@
#ifndef PROPERTY_MAPS_FOR_EDIT_PLUGIN
#define PROPERTY_MAPS_FOR_EDIT_PLUGIN
#include "Polyhedron_type.h"
template<class P>
class Polyhedron_vertex_deformation_index_map
{
private:
typedef P Polyhedron ;
public:
typedef boost::read_write_property_map_tag category;
typedef std::size_t value_type;
typedef std::size_t reference;
typedef typename boost::graph_traits<Polyhedron>::vertex_descriptor key_type;
Polyhedron_vertex_deformation_index_map()
{
}
};
template<class P>
std::size_t
get( Polyhedron_vertex_deformation_index_map<P>, typename P::Vertex_handle vh)
{
return vh->id();
}
template<class P>
void
put( Polyhedron_vertex_deformation_index_map<P>&, typename P::Vertex_handle vh, std::size_t s)
{
vh->id() = s;
}
template<class P>
class Polyhedron_edge_deformation_index_map
{
private:
typedef P Polyhedron ;
public:
typedef boost::read_write_property_map_tag category;
typedef std::size_t value_type;
typedef std::size_t reference;
typedef typename boost::graph_traits<Polyhedron>::edge_descriptor key_type;
Polyhedron_edge_deformation_index_map()
{}
};
namespace boost {
template<class P>
std::size_t
get( Polyhedron_edge_deformation_index_map<P> pmap, typename P::Halfedge_handle eh)
{
return eh->id();
}
template<class P>
void
put( Polyhedron_edge_deformation_index_map<P>& pmap, typename P::Halfedge_handle eh, std::size_t s)
{
eh->id() = s;
}
}
template<class P>
class Polyhedron_edge_deformation_length_map
{
private:
typedef P Polyhedron ;
public:
std::vector<double>& m_lengths;
typedef boost::read_write_property_map_tag category;
typedef double value_type;
typedef double& reference;
typedef typename boost::graph_traits<Polyhedron>::edge_descriptor key_type;
Polyhedron_edge_deformation_length_map(const P&,std::vector<double>& lengths)
: m_lengths(lengths) {}
};
namespace boost {
template<class P>
double
get( Polyhedron_edge_deformation_length_map<P> pmap, typename P::Halfedge_handle eh)
{
CGAL_assertion( pmap.m_lengths.size() > eh->id() );
return pmap.m_lengths[eh->id()];
}
template<class P>
void
put( Polyhedron_edge_deformation_length_map<P>& pmap, typename P::Halfedge_handle eh, double s)
{
CGAL_assertion( pmap.m_lengths.size() > eh->id() );
pmap.m_lengths[eh->id()] = s;
}
}
#endif //PROPERTY_MAPS_FOR_EDIT_PLUGIN

View File

@ -3,6 +3,11 @@
#include "Polyhedron_type.h" #include "Polyhedron_type.h"
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <algorithm>
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
#include <CGAL/boost/graph/properties_Polyhedron_3.h>
#include "Property_maps_for_edit_plugin.h"
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <QVariant> #include <QVariant>
#include <set> #include <set>
@ -14,35 +19,86 @@
#include <QGLViewer/manipulatedFrame.h> #include <QGLViewer/manipulatedFrame.h>
typedef Polyhedron::Vertex_handle Vertex_handle; typedef Polyhedron::Vertex_handle Vertex_handle;
typedef Polyhedron::Halfedge_handle Halfedge_handle;
typedef std::set<Vertex_handle> Selected_vertices; typedef std::set<Vertex_handle> Selected_vertices;
typedef std::vector<std::pair<Kernel::Point_3, Kernel::Point_3> > Transform_vectors;
typedef Selected_vertices::iterator Selected_vertices_it; typedef Selected_vertices::iterator Selected_vertices_it;
typedef Polyhedron_vertex_deformation_index_map<Polyhedron> Vertex_index_map;
typedef Polyhedron_edge_deformation_length_map<Polyhedron> Edge_length_map;
typedef boost::iterator_property_map<std::vector<double>::iterator, Vertex_index_map> Dist_pmap;
#define PI 3.14159265359
struct Scene_edit_polyhedron_item_priv { struct Scene_edit_polyhedron_item_priv {
Scene_polyhedron_item* poly_item; Scene_polyhedron_item* poly_item;
int zone_size; int handlesRegionSize;
int interestRegionSize;
bool geodesicCircle;
bool sharpFeature;
int usageScenario;
bool selected_vertex_changed;
bool selected_handles_moved;
qglviewer::ManipulatedFrame* frame; qglviewer::ManipulatedFrame* frame;
Selected_vertices selected_vertices; Selected_vertices selected_handles;
Selected_vertices non_selected_handles;
Selected_vertices selected_roi;
Selected_vertices non_selected_roi;
Vertex_handle selected_vertex; Vertex_handle selected_vertex;
Transform_vectors selected_vectors;
Transform_vectors non_selected_vectors;
Kernel::Point_3 orig_pos; Kernel::Point_3 orig_pos;
Kernel::Point_3 last_pos;
Vertex_index_map* vertex_index_map;
std::vector<double> geodesic_distance;
Dist_pmap* dist_pmap;
std::vector<bool> is_sharp_vertices;
}; // end struct Scene_edit_polyhedron_item_priv }; // end struct Scene_edit_polyhedron_item_priv
Scene_edit_polyhedron_item::Scene_edit_polyhedron_item(Scene_polyhedron_item* poly_item) Scene_edit_polyhedron_item::Scene_edit_polyhedron_item(Scene_polyhedron_item* poly_item)
: d(new Scene_edit_polyhedron_item_priv) : d(new Scene_edit_polyhedron_item_priv)
{ {
d->poly_item = poly_item; d->poly_item = poly_item;
d->zone_size = 0; d->handlesRegionSize = 0;
d->frame = new ManipulatedFrame(); d->frame = new ManipulatedFrame();
d->frame->setProperty("item", QVariant::fromValue<QObject*>(this)); d->frame->setProperty("item", QVariant::fromValue<QObject*>(this));
if(!connect(poly_item, SIGNAL(selected_vertex(void*)), if(!connect(poly_item, SIGNAL(selected_vertex(void*)),
this, SLOT(vertex_has_been_selected(void*)))) this, SLOT(vertex_has_been_selected(void*))))
std::cerr << __FILE__ << ": connection failed!\n"; std::cerr << __FILE__ << ": connection failed!\n";
poly_item->enable_facets_picking(true); poly_item->enable_facets_picking(true);
d->vertex_index_map = new Vertex_index_map();
int idx = 0;
for ( Vertex_handle vh = poly_item->polyhedron()->vertices_begin(); vh != poly_item->polyhedron()->vertices_end(); vh++ )
{
put(*d->vertex_index_map, vh, idx++);
}
std::vector<double> lengths(poly_item->polyhedron()->size_of_halfedges(),0);
Edge_length_map edge_length_map(*poly_item->polyhedron(),lengths);
for ( Halfedge_handle eh = poly_item->polyhedron()->edges_begin(); eh != poly_item->polyhedron()->edges_end(); eh++ )
{
Kernel::Vector_3 edge = eh->vertex()->point() - eh->opposite()->vertex()->point();
double edge_length = std::sqrt(edge.squared_length());
boost::put(edge_length_map, eh, edge_length);
}
d->geodesic_distance.resize(boost::num_vertices(*poly_item->polyhedron()), 0);
d->dist_pmap = new Dist_pmap(d->geodesic_distance.begin(), *d->vertex_index_map);
find_sharp_vertices_1();
connect(d->frame, SIGNAL(modified()),
this, SIGNAL(modified()));
} }
Scene_edit_polyhedron_item::~Scene_edit_polyhedron_item() Scene_edit_polyhedron_item::~Scene_edit_polyhedron_item()
{ {
delete d->frame; delete d->frame;
delete d->vertex_index_map;
delete d->dist_pmap;
delete d; delete d;
} }
@ -73,19 +129,78 @@ Scene_edit_polyhedron_item::toolTip() const
void Scene_edit_polyhedron_item::draw() const { void Scene_edit_polyhedron_item::draw() const {
d->poly_item->direct_draw(); d->poly_item->direct_draw();
if(!d->selected_vertices.empty()) { if(!d->non_selected_handles.empty() || !d->non_selected_roi.empty()
|| !d->selected_handles.empty() || !d->selected_roi.empty() ) {
CGAL::GL::Point_size point_size; point_size.set_point_size(5); CGAL::GL::Point_size point_size; point_size.set_point_size(5);
CGAL::GL::Color color; color.set_rgb_color(0, 0, 0); CGAL::GL::Color color;
color.set_rgb_color(1.f, 0, 0);
::glBegin(GL_POINTS); ::glBegin(GL_POINTS);
for(Selected_vertices_it for(Selected_vertices_it
it = d->selected_vertices.begin(), it = d->selected_handles.begin(),
end = d->selected_vertices.end(); end = d->selected_handles.end();
it != end; ++it)
{
const Kernel::Point_3& p = (*it)->point();
::glVertex3d(p.x(), p.y(), p.z());
}
::glEnd();
color.set_rgb_color(1.f, 0.5f, 0);
::glBegin(GL_POINTS);
for(Selected_vertices_it
it = d->non_selected_handles.begin(),
end = d->non_selected_handles.end();
it != end; ++it) it != end; ++it)
{ {
const Kernel::Point_3& p = (*it)->point(); const Kernel::Point_3& p = (*it)->point();
::glVertex3d(p.x(), p.y(), p.z()); ::glVertex3d(p.x(), p.y(), p.z());
} }
::glEnd(); ::glEnd();
color.set_rgb_color(0, 1.f, 0);
::glBegin(GL_POINTS);
for(Selected_vertices_it
it = d->selected_roi.begin(),
end = d->selected_roi.end();
it != end; ++it)
{
const Kernel::Point_3& p = (*it)->point();
::glVertex3d(p.x(), p.y(), p.z());
}
::glEnd();
color.set_rgb_color(0, 1.f, 0);
::glBegin(GL_POINTS);
for(Selected_vertices_it
it = d->non_selected_roi.begin(),
end = d->non_selected_roi.end();
it != end; ++it)
{
const Kernel::Point_3& p = (*it)->point();
::glVertex3d(p.x(), p.y(), p.z());
}
::glEnd();
color.set_rgb_color(1.f, 0, 0);
::glBegin(GL_LINES);
for (std::size_t i = 0; i < d->selected_vectors.size(); i++)
{
const Kernel::Point_3& p0 = d->selected_vectors[i].first;
const Kernel::Point_3& p1 = d->selected_vectors[i].second;
::glVertex3d(p0.x(), p0.y(), p0.z());
::glVertex3d(p1.x(), p1.y(), p1.z());
}
::glEnd();
color.set_rgb_color(1.f, 0.5f, 0);
::glBegin(GL_LINES);
for (std::size_t i = 0; i < d->non_selected_vectors.size(); i++)
{
const Kernel::Point_3& p0 = d->non_selected_vectors[i].first;
const Kernel::Point_3& p1 = d->non_selected_vectors[i].second;
::glVertex3d(p0.x(), p0.y(), p0.z());
::glVertex3d(p1.x(), p1.y(), p1.z());
}
::glEnd();
} }
} }
@ -111,7 +226,7 @@ changed()
{ {
d->poly_item->changed(); d->poly_item->changed();
Scene_item::changed(); Scene_item::changed();
d->orig_pos = current_position(); d->last_pos = current_position();
} }
void void
@ -141,19 +256,72 @@ Scene_polyhedron_item* Scene_edit_polyhedron_item::to_polyhedron_item() const {
} }
void void
Scene_edit_polyhedron_item::setZoneSize(int i) { Scene_edit_polyhedron_item::setHandlesRegionSize(int i) {
if(i >= 0) { if(i >= 0) {
std::cerr << "item \"" << qPrintable(name()) d->handlesRegionSize = i;
<< "\".setZoneSize(" << i << ")\n"; if(d->selected_vertex != Vertex_handle()) {
d->zone_size = i; vertex_has_been_selected(&*d->selected_vertex);
}
} }
} }
void
Scene_edit_polyhedron_item::setInterestRegionSize(int i) {
if(i >= 0) {
d->interestRegionSize = i;
if(d->selected_vertex != Vertex_handle()) {
vertex_has_been_selected(&*d->selected_vertex);
}
}
}
void
Scene_edit_polyhedron_item::setGeodesicCircle(bool status) {
d->geodesicCircle = status;
if(d->selected_vertex != Vertex_handle()) {
vertex_has_been_selected(&*d->selected_vertex);
}
}
void
Scene_edit_polyhedron_item::setSharpFeature(bool status) {
d->sharpFeature = status;
if(d->selected_vertex != Vertex_handle()) {
vertex_has_been_selected(&*d->selected_vertex);
}
}
void
Scene_edit_polyhedron_item::setUsageScenario(int i) {
d->usageScenario = i;
}
void
Scene_edit_polyhedron_item::setSelectedVertexChanged(bool status) {
d->selected_vertex_changed = status;
}
void
Scene_edit_polyhedron_item::setSelectedHandlesMoved(bool status) {
d->selected_handles_moved = status;
}
qglviewer::ManipulatedFrame* qglviewer::ManipulatedFrame*
Scene_edit_polyhedron_item::manipulatedFrame() { Scene_edit_polyhedron_item::manipulatedFrame() {
return d->frame; return d->frame;
} }
void
Scene_edit_polyhedron_item::setSelectedVector(Kernel::Vector_3 translation_last)
{
for (std::size_t i = 0; i < d->selected_vectors.size(); i++)
{
Kernel::Point_3 old_position = d->selected_vectors[i].second;
Kernel::Point_3 new_position = old_position + translation_last;
d->selected_vectors[i].second = new_position;
}
}
struct Get_vertex_handle : public CGAL::Modifier_base<Polyhedron::HDS> struct Get_vertex_handle : public CGAL::Modifier_base<Polyhedron::HDS>
{ {
Polyhedron::Vertex* vertex_ptr; Polyhedron::Vertex* vertex_ptr;
@ -163,6 +331,232 @@ struct Get_vertex_handle : public CGAL::Modifier_base<Polyhedron::HDS>
} }
}; };
double Scene_edit_polyhedron_item::dihedral_angle(edge_descriptor e)
{
Polyhedron* poly = d->poly_item->polyhedron();
vertex_descriptor v0 = boost::target(e, *poly);
vertex_descriptor v1 = boost::source(e, *poly);
// Only one triangle for border edges
if (boost::get(CGAL::edge_is_border, *poly, e)||boost::get(CGAL::edge_is_border, *poly, CGAL::opposite_edge(e, *poly)))
{
return -1;
}
else
{
edge_descriptor e_cw = CGAL::next_edge_cw(e, *poly);
vertex_descriptor v2 = boost::source(e_cw, *poly);
edge_descriptor e_ccw = CGAL::next_edge_ccw(e, *poly);
vertex_descriptor v3 = boost::source(e_ccw, *poly);
Kernel::Vector_3 e01 = v1->point() - v0->point();
Kernel::Vector_3 e02 = v2->point() - v0->point();
Kernel::Vector_3 e03 = v3->point() - v0->point();
// compute dihedral angle between v0_v1_v2 and v0_v1_v3
// cross(e01, e02)
Kernel::Vector_3 n012( e01[1]*e02[2]-e01[2]*e02[1], e01[2]*e02[0]-e01[0]*e02[2], e01[0]*e02[1]-e01[1]*e02[0] );
// cross(e01, e03)
Kernel::Vector_3 n013( e01[1]*e03[2]-e01[2]*e03[1], e01[2]*e03[0]-e01[0]*e03[2], e01[0]*e03[1]-e01[1]*e03[0] );
// n012*n013 / (|n012|*|n013|)
double cos_angle = (n012[0]*n013[0]+n012[1]*n013[1]+n012[2]*n013[2]) / std::sqrt(n012.squared_length()*n013.squared_length());
return acos(cos_angle);
}
}
void
Scene_edit_polyhedron_item::find_sharp_vertices()
{
Polyhedron* poly = d->poly_item->polyhedron();
d->is_sharp_vertices.clear();
d->is_sharp_vertices.resize(poly->size_of_vertices(), false);
std::vector<double> dihedral_angles;
vertex_iterator vb, ve;
for ( boost::tie(vb,ve) = boost::vertices(*poly); vb != ve; vb++ )
{
// compute dihedral angles
in_edge_iterator eb, ee;
dihedral_angles.clear();
double sum = 0;
for ( boost::tie(eb,ee) = boost::in_edges(*vb, *poly); eb != ee; eb++ )
{
double angle = dihedral_angle(*eb);
if (angle != -1)
{
dihedral_angles.push_back(angle);
sum += angle;
}
}
// compute variance of angles
double ave_angle = sum/dihedral_angles.size();
double var = 0;
for ( std::size_t i = 0; i < dihedral_angles.size(); i++ )
{
var += (dihedral_angles[i] - ave_angle)*(dihedral_angles[i] - ave_angle)/dihedral_angles.size();
}
if (var > 0.2)
{
d->is_sharp_vertices[ get(*d->vertex_index_map, *vb) ] = true ;
}
}
}
void
Scene_edit_polyhedron_item::find_sharp_vertices_1()
{
Polyhedron* poly = d->poly_item->polyhedron();
d->is_sharp_vertices.clear();
d->is_sharp_vertices.resize(poly->size_of_vertices(), false);
vertex_iterator vb, ve;
for ( boost::tie(vb,ve) = boost::vertices(*poly); vb != ve; vb++ )
{
// compute dihedral angles
in_edge_iterator eb, ee;
for ( boost::tie(eb,ee) = boost::in_edges(*vb, *poly); eb != ee; eb++ )
{
double angle = dihedral_angle(*eb);
if (angle < PI*3.0/4.0)
{
d->is_sharp_vertices[ get(*d->vertex_index_map, *vb) ] = true;
break;
}
}
}
}
Selected_vertices extend_once(Selected_vertices selected_vertices)
{
std::set<Vertex_handle> original_set = selected_vertices;
BOOST_FOREACH(Vertex_handle v, original_set) {
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( selected_vertices.find(other_v) == selected_vertices.end() )
{
selected_vertices.insert(other_v);
}
} while(++he_it != he_it_end);
}
}
return selected_vertices;
}
// extend k-neighboring vertices
Selected_vertices extend_k_ring(Selected_vertices selected_vertices, int k)
{
std::vector<Vertex_handle> selected_vertices_vector;
selected_vertices_vector.insert(selected_vertices_vector.begin(), selected_vertices.begin(), selected_vertices.end());
int idx_lv = 0; // pointing the neighboring vertices on current level
int idx_lv_end;
for ( int lv = 0; lv < k; lv++ )
{
idx_lv_end = selected_vertices_vector.size();
for (; idx_lv < idx_lv_end; idx_lv++)
{
Vertex_handle v = selected_vertices_vector[idx_lv];
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();
std::vector<Vertex_handle>::iterator
it = std::find(selected_vertices_vector.begin(), selected_vertices_vector.end(), other_v);
if (it == selected_vertices_vector.end())
{
selected_vertices_vector.push_back(other_v);
selected_vertices.insert(other_v);
}
} while(++he_it != he_it_end);
}
}
}
return selected_vertices;
}
// extend vertices inside specific radius, so that the selected region is close circle
Selected_vertices extend_circle(Selected_vertices selected_vertices, double radius, Dist_pmap dist_pmap)
{
std::vector<Vertex_handle> selected_vertices_vector;
selected_vertices_vector.insert(selected_vertices_vector.begin(), selected_vertices.begin(), selected_vertices.end());
bool new_vertex_selected = true;
int idx_lv = 0; // pointing the neighboring vertices on current level
int idx_lv_end;
while (new_vertex_selected)
{
new_vertex_selected = false;
idx_lv_end = selected_vertices_vector.size();
for (; idx_lv < idx_lv_end; idx_lv++)
{
Vertex_handle v = selected_vertices_vector[idx_lv];
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( boost::get(dist_pmap, other_v) <= radius )
{
std::vector<Vertex_handle>::iterator it = std::find(selected_vertices_vector.begin(), selected_vertices_vector.end(), other_v);
if (it == selected_vertices_vector.end())
{
selected_vertices_vector.push_back(other_v);
selected_vertices.insert(other_v);
new_vertex_selected = true;
}
}
} while(++he_it != he_it_end);
}
}
}
return selected_vertices;
}
// extend vertices until reaching the sharp edges
Selected_vertices extend_sharp_edge(Selected_vertices selected_vertices, std::vector<bool> is_sharp_vertices, Vertex_index_map vertex_index_map)
{
std::vector<Vertex_handle> selected_vertices_vector;
selected_vertices_vector.insert(selected_vertices_vector.begin(), selected_vertices.begin(), selected_vertices.end());
bool new_vertex_selected = true;
int idx_lv = 0; // pointing the neighboring vertices on current level
int idx_lv_end;
while (new_vertex_selected)
{
new_vertex_selected = false;
idx_lv_end = selected_vertices_vector.size();
for (; idx_lv < idx_lv_end; idx_lv++)
{
Vertex_handle v = selected_vertices_vector[idx_lv];
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();
int idx = get(vertex_index_map, other_v);
if( !is_sharp_vertices[idx] )
{
std::vector<Vertex_handle>::iterator it = std::find(selected_vertices_vector.begin(), selected_vertices_vector.end(), other_v);
if (it == selected_vertices_vector.end())
{
selected_vertices_vector.push_back(other_v);
selected_vertices.insert(other_v);
new_vertex_selected = true;
}
}
} while(++he_it != he_it_end);
}
}
}
return selected_vertices;
}
void Scene_edit_polyhedron_item::vertex_has_been_selected(void* void_ptr) { void Scene_edit_polyhedron_item::vertex_has_been_selected(void* void_ptr) {
Polyhedron* poly = d->poly_item->polyhedron(); Polyhedron* poly = d->poly_item->polyhedron();
@ -174,66 +568,351 @@ void Scene_edit_polyhedron_item::vertex_has_been_selected(void* void_ptr) {
poly->delegate(get_vertex_handle); poly->delegate(get_vertex_handle);
Vertex_handle vh = get_vertex_handle.vh; Vertex_handle vh = get_vertex_handle.vh;
if (d->selected_vertex != vh)
std::cerr << "Selected vertex: " << void_ptr << " = " << vh->point() {
<< std::endl; // re-compute geodesic distances relative to selected_vertex
d->selected_vertices.clear(); std::vector<double> lengths(poly->size_of_halfedges(),0);
Edge_length_map edge_length_map(*poly,lengths);
d->selected_vertices.insert(vh);
for ( Halfedge_handle eh = poly->edges_begin(); eh != poly->edges_end(); eh++ )
std::cerr << "d->zone_size = " << d->zone_size << std::endl; {
// Naive way to compute the k-neighborhood of vh, with k==d->zone_size. Kernel::Vector_3 edge = eh->vertex()->point() - eh->opposite()->vertex()->point();
for(int i = 0; i < d->zone_size; ++i) { double edge_length = std::sqrt(edge.squared_length());
std::set<Vertex_handle> selected_vertices; boost::put(edge_length_map, eh, edge_length);
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) { boost::dijkstra_shortest_paths( *poly, vh,
Polyhedron::Halfedge_around_vertex_circulator boost::vertex_index_map (*d->vertex_index_map).
he_it = v->vertex_begin(), he_it_end(he_it); weight_map (edge_length_map).
if(he_it != 0) { distance_map (*d->dist_pmap));
do { }
const Vertex_handle other_v = he_it->opposite()->vertex();
if( d->selected_vertices.find(other_v) == d->selected_vertices.end() ) // set new handles and ROI regions
{ Selected_vertices new_handles;
d->selected_vertices.insert(other_v); new_handles.insert(vh);
} new_handles = extend_k_ring(new_handles, d->handlesRegionSize);
} while(++he_it != he_it_end); Selected_vertices new_roi;
if (d->sharpFeature)
{
new_roi.insert(vh);
new_roi = extend_sharp_edge(new_roi, d->is_sharp_vertices, *d->vertex_index_map);
}
else
{
new_roi = new_handles;
new_roi = extend_k_ring( new_roi, d->interestRegionSize - d->handlesRegionSize );
if (d->geodesicCircle)
{
double radius = 0;
BOOST_FOREACH(Vertex_handle v, new_handles)
{
double dist = boost::get(*d->dist_pmap, v);
if ( dist> radius ) radius = dist;
} }
new_handles = extend_circle(new_handles, radius, *d->dist_pmap);
radius = 0;
BOOST_FOREACH(Vertex_handle v, new_roi)
{
double dist = boost::get(*d->dist_pmap, v);
if ( dist> radius ) radius = dist;
}
new_roi = extend_circle(new_roi, radius, *d->dist_pmap);
} }
} }
// multiple handles scenario
if (d->usageScenario == 1)
{
if (d->selected_vertex != vh) // selected_vertex changed
{
BOOST_FOREACH(Vertex_handle v, new_handles)
{
if ( d->non_selected_handles.find(v) != d->non_selected_handles.end() ||
d->selected_handles.find(v) != d->selected_handles.end() )
{
std::cerr << "New handles rejected: overlapped!\n";
return;
}
}
BOOST_FOREACH(Vertex_handle v, d->selected_handles)
{
// add the latest handles into non_selected_handles
if ( d->non_selected_handles.find(v) == d->non_selected_handles.end() )
{
d->non_selected_handles.insert(v);
}
}
BOOST_FOREACH(Vertex_handle v, d->selected_roi)
{
// add the latest ROI into non_selected_roi
if ( d->non_selected_roi.find(v) == d->non_selected_roi.end() )
{
d->non_selected_roi.insert(v);
}
}
for (std::size_t i = 0; i < d->selected_vectors.size(); i++)
{
std::pair<Kernel::Point_3, Kernel::Point_3> v = d->selected_vectors[i];
Transform_vectors::iterator it = find(d->non_selected_vectors.begin(), d->non_selected_vectors.end(), v );
// add the latest transform vectors into non_selected_vectors
if ( it == d->non_selected_vectors.end() )
{
d->non_selected_vectors.push_back(v);
}
}
}
else
{
BOOST_FOREACH(Vertex_handle v, new_handles)
{
if ( d->non_selected_handles.find(v) != d->non_selected_handles.end() )
{
std::cerr << "New handles rejected: overlapped!\n";
return;
}
}
if (d->selected_handles_moved)
{
std::cerr << "Update of old handles rejected: already moved!\n";
return;
}
}
d->selected_vectors.clear();
std::pair<Kernel::Point_3, Kernel::Point_3> v(vh->point(), vh->point());
d->selected_vectors.push_back(v);
}
d->selected_vertex = vh;
d->selected_handles = new_handles;
d->selected_handles_moved = false;
d->selected_roi = new_roi;
std::cerr << d->handlesRegionSize << " " << d->interestRegionSize << std::endl;
const Kernel::Point_3& p = vh->point(); const Kernel::Point_3& p = vh->point();
d->orig_pos = p; d->orig_pos = p;
d->last_pos = p;
d->frame->setPosition(qglviewer::Vec(p.x(), p.y(), p.z())); d->frame->setPosition(qglviewer::Vec(p.x(), p.y(), p.z()));
connect(d->frame, SIGNAL(modified()),
this, SIGNAL(modified()));
emit begin_edit(); emit begin_edit();
} }
void Scene_edit_polyhedron_item::vertex_has_been_selected_2(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;
if (d->selected_vertex != vh)
{
d->selected_vertex_changed = true;
d->selected_vertex = vh;
}
else
{
d->selected_vertex_changed = false;
}
if (d->selected_handles_moved) // re-compute variance of dihedral angles for each vertex
{
find_sharp_vertices_1();
}
if (d->selected_vertex_changed || d->selected_handles_moved) // selected_vertex is changed or moved
{
// compute geodesic distances relative to selected_vertex
std::vector<double> lengths(poly->size_of_halfedges(),0);
Edge_length_map edge_length_map(*poly,lengths);
for ( Halfedge_handle eh = poly->edges_begin(); eh != poly->edges_end(); eh++ )
{
Kernel::Vector_3 edge = eh->vertex()->point() - eh->opposite()->vertex()->point();
double edge_length = std::sqrt(edge.squared_length());
boost::put(edge_length_map, eh, edge_length);
}
boost::dijkstra_shortest_paths( *poly, vh,
boost::vertex_index_map (*d->vertex_index_map).
weight_map (edge_length_map).
distance_map (*d->dist_pmap));
if (d->usageScenario == 1)
{
BOOST_FOREACH(Vertex_handle v, d->selected_handles)
{
// add the latest handles into non_selected_handles
if ( d->non_selected_handles.find(v) == d->non_selected_handles.end() )
{
d->non_selected_handles.insert(v);
}
}
BOOST_FOREACH(Vertex_handle v, d->selected_roi)
{
// add the latest ROI into non_selected_roi
if ( d->non_selected_roi.find(v) == d->non_selected_roi.end() )
{
d->non_selected_roi.insert(v);
}
}
}
}
d->selected_handles.clear();
d->selected_handles.insert(vh);
// compute the k-neighborhood of vh, with k==d->handlesRegionSize.
d->selected_handles = extend_k_ring(d->selected_handles, d->handlesRegionSize);
d->selected_handles_moved = false;
d->selected_roi = d->selected_handles;
std::cerr << d->handlesRegionSize << " " << d->interestRegionSize << std::endl;
d->selected_roi = extend_k_ring( d->selected_roi, d->interestRegionSize - d->handlesRegionSize );
//d->selected_roi = extend_sharp_edge(d->selected_roi, 0.2, d->dihedral_angle_variance, *d->vertex_index_map);
// add geodesic distance constraints into handles and ROI vertices
if (d->geodesicCircle)
{
double radius = 0;
BOOST_FOREACH(Vertex_handle v, d->selected_handles)
{
double dist = boost::get(*d->dist_pmap, v);
if ( dist> radius ) radius = dist;
}
d->selected_handles = extend_circle(d->selected_handles, radius, *d->dist_pmap);
radius = 0;
BOOST_FOREACH(Vertex_handle v, d->selected_roi)
{
double dist = boost::get(*d->dist_pmap, v);
if ( dist> radius ) radius = dist;
}
d->selected_roi = extend_circle(d->selected_roi, radius, *d->dist_pmap);
}
const Kernel::Point_3& p = vh->point();
d->orig_pos = p;
d->last_pos = p;
d->frame->setPosition(qglviewer::Vec(p.x(), p.y(), p.z()));
emit begin_edit();
}
Vertex_handle Vertex_handle
Scene_edit_polyhedron_item::selected_vertex() const { Scene_edit_polyhedron_item::selected_vertex() const {
return d->selected_vertex; return d->selected_vertex;
} }
QList<Vertex_handle> QList<Vertex_handle>
Scene_edit_polyhedron_item::selected_vertices() const { Scene_edit_polyhedron_item::selected_handles() const {
QList<Vertex_handle> result; QList<Vertex_handle> result;
BOOST_FOREACH(Vertex_handle vh, d->selected_vertices) { BOOST_FOREACH(Vertex_handle vh, d->selected_handles) {
result << vh; result << vh;
} }
return result; return result;
} }
QList<Vertex_handle>
Scene_edit_polyhedron_item::non_selected_handles() const {
QList<Vertex_handle> result;
BOOST_FOREACH(Vertex_handle vh, d->non_selected_handles) {
result << vh;
}
return result;
}
QList<Vertex_handle>
Scene_edit_polyhedron_item::selected_roi() const {
QList<Vertex_handle> result;
BOOST_FOREACH(Vertex_handle vh, d->selected_roi) {
result << vh;
}
return result;
}
std::pair<Kernel::Point_3, Kernel::Point_3>
Scene_edit_polyhedron_item::selected_vector() const {
std::pair<Kernel::Point_3, Kernel::Point_3> result;
if (!d->selected_vectors.empty())
{
result = d->selected_vectors[0];
}
return result;
}
QList<Vertex_handle>
Scene_edit_polyhedron_item::non_selected_roi() const {
QList<Vertex_handle> result;
BOOST_FOREACH(Vertex_handle vh, d->non_selected_roi) {
result << vh;
}
return result;
}
void Scene_edit_polyhedron_item::clear_non_selected_roi() {
d->non_selected_roi.clear();
}
void Scene_edit_polyhedron_item::clear_selected_roi() {
d->selected_roi.clear();
}
void Scene_edit_polyhedron_item::clear_non_selected_handles() {
d->non_selected_handles.clear();
}
void Scene_edit_polyhedron_item::clear_selected_handles() {
d->selected_handles.clear();
d->selected_vertex = Vertex_handle();
}
void Scene_edit_polyhedron_item::clear_selected_vectors() {
d->selected_vectors.clear();
}
void Scene_edit_polyhedron_item::clear_non_selected_vectors() {
d->non_selected_vectors.clear();
}
int Scene_edit_polyhedron_item::usage_scenario() {
return d->usageScenario;
}
Kernel::Point_3 Scene_edit_polyhedron_item::current_position() const { Kernel::Point_3 Scene_edit_polyhedron_item::current_position() const {
const qglviewer::Vec vec = d->frame->position(); const qglviewer::Vec vec = d->frame->position();
return Kernel::Point_3(vec.x, vec.y, vec.z); return Kernel::Point_3(vec.x, vec.y, vec.z);
} }
Kernel::Point_3 Scene_edit_polyhedron_item::last_position() const {
return d->last_pos;
}
Kernel::Point_3 Scene_edit_polyhedron_item::original_position() const { Kernel::Point_3 Scene_edit_polyhedron_item::original_position() const {
return d->orig_pos; return d->orig_pos;
} }
void Scene_edit_polyhedron_item::setVisible(bool b) {
d->poly_item->setVisible(b);
Scene_item::setVisible(b);
}
void Scene_edit_polyhedron_item::setColor(QColor c) {
d->poly_item->setColor(c);
Scene_item::setColor(c);
}
void Scene_edit_polyhedron_item::setName(QString n) {
Scene_item::setName(n);
n.replace(" (edit)", "");
d->poly_item->setName(n);
}
void Scene_edit_polyhedron_item::setRenderingMode(RenderingMode m) {
d->poly_item->setRenderingMode(m);
Scene_item::setRenderingMode(m);
}
#include "Scene_edit_polyhedron_item.moc" #include "Scene_edit_polyhedron_item.moc"

View File

@ -4,6 +4,8 @@
#include "Scene_edit_polyhedron_item_config.h" #include "Scene_edit_polyhedron_item_config.h"
#include "Scene_polyhedron_item.h" #include "Scene_polyhedron_item.h"
#include "Polyhedron_type.h" #include "Polyhedron_type.h"
#include <CGAL/boost/graph/halfedge_graph_traits_Polyhedron_3.h>
#include <CGAL/boost/graph/properties.h>
#include <iostream> #include <iostream>
#include <vector> #include <vector>
@ -14,6 +16,12 @@
class QMenu; class QMenu;
struct Scene_edit_polyhedron_item_priv; struct Scene_edit_polyhedron_item_priv;
typedef boost::graph_traits<Polyhedron>::vertex_descriptor vertex_descriptor;
typedef boost::graph_traits<Polyhedron>::vertex_iterator vertex_iterator;
typedef boost::graph_traits<Polyhedron>::edge_descriptor edge_descriptor;
typedef boost::graph_traits<Polyhedron>::edge_iterator edge_iterator;
typedef boost::graph_traits<Polyhedron>::in_edge_iterator in_edge_iterator;
// This class represents a polyhedron in the OpenGL scene // This class represents a polyhedron in the OpenGL scene
class SCENE_EDIT_POLYHEDRON_ITEM_EXPORT Scene_edit_polyhedron_item class SCENE_EDIT_POLYHEDRON_ITEM_EXPORT Scene_edit_polyhedron_item
: public Scene_item { : public Scene_item {
@ -35,6 +43,11 @@ public:
// Function for displaying meta-data of the item // Function for displaying meta-data of the item
QString toolTip() const; QString toolTip() const;
void setColor(QColor c);
void setName(QString n);
void setVisible(bool b);
void setRenderingMode(RenderingMode m);
// // Function to override the context menu // // Function to override the context menu
// QMenu* contextMenu(); // QMenu* contextMenu();
@ -53,8 +66,31 @@ public:
// Functions related to the edition // Functions related to the edition
Kernel::Point_3 original_position() const; Kernel::Point_3 original_position() const;
Kernel::Point_3 current_position() const; Kernel::Point_3 current_position() const;
Kernel::Point_3 last_position() const;
Polyhedron::Vertex_handle selected_vertex() const; Polyhedron::Vertex_handle selected_vertex() const;
QList<Polyhedron::Vertex_handle> selected_vertices() const;
QList<Polyhedron::Vertex_handle> selected_handles() const;
QList<Polyhedron::Vertex_handle> non_selected_handles() const;
QList<Polyhedron::Vertex_handle> selected_roi() const;
QList<Polyhedron::Vertex_handle> non_selected_roi() const;
std::pair<Kernel::Point_3, Kernel::Point_3> selected_vector() const;
void clear_selected_roi();
void clear_non_selected_roi();
void clear_selected_handles();
void clear_non_selected_handles();
void clear_selected_vectors();
void clear_non_selected_vectors();
int usage_scenario();
void setSelectedVertexChanged(bool status);
void setSelectedHandlesMoved(bool status);
void setSelectedVector(Kernel::Vector_3 translation_last);
double dihedral_angle(edge_descriptor e);
void find_sharp_vertices();
void find_sharp_vertices_1();
/// @deprecated
QList<Polyhedron::Vertex_handle> selected_vertices()
{ return selected_handles(); }
/// Returns a Scene_polyhedron_item from the edit polyhedron item, and /// Returns a Scene_polyhedron_item from the edit polyhedron item, and
/// transfer the ownership of the polyhedron to it. /// transfer the ownership of the polyhedron to it.
@ -74,8 +110,14 @@ public slots:
double dir_x, double dir_x,
double dir_y, double dir_y,
double dir_z); double dir_z);
void setZoneSize(int i); void setZoneSize(int i) { setHandlesRegionSize(i); } /// @deprecated
void setHandlesRegionSize(int i);
void setInterestRegionSize(int i);
void setGeodesicCircle(bool status);
void setSharpFeature(bool status);
void setUsageScenario(int i);
void vertex_has_been_selected(void* vertex_handle); void vertex_has_been_selected(void* vertex_handle);
void vertex_has_been_selected_2(void* vertex_handle);
signals: signals:
void begin_edit(); void begin_edit();

View File

@ -0,0 +1,15 @@
OFF
7 6 0
-215.983 70.3187 137.883
-216.952 39.6826 144.676
-207.932 -24.8993 148.723
-247.708 69.538 123.733
-246.196 45.203 131.288
-246.937 14.9498 134.175
-255.988 45.6255 130.774
3 3 4 0
3 1 0 4
3 5 2 4
3 1 4 2
3 4 3 6
3 4 6 5

View File

@ -68,7 +68,7 @@ public:
// Public operations // Public operations
public: public:
Eigen_solver_traits(): m_solver_sptr(new EigenSolverT) Eigen_solver_traits():m_mat(NULL), m_solver_sptr(new EigenSolverT)
{ {
} }
@ -93,8 +93,25 @@ public:
return m_solver_sptr->info() == Eigen::Success; return m_solver_sptr->info() == Eigen::Success;
} }
bool pre_factor (const Matrix& A, NT& D)
{
D = 1;
m_mat = &A.eigen_object();
solver().compute(*m_mat);
return solver().info() == Eigen::Success;
}
bool linear_solver(const Vector& B, Vector& X)
{
CGAL_precondition(m_mat!=NULL); //pre_factor should have been called first
X = solver().solve(B);
return solver().info() == Eigen::Success;
}
protected: protected:
boost::shared_ptr<EigenSolverT> m_solver_sptr; boost::shared_ptr<EigenSolverT> m_solver_sptr;
const typename Matrix::EigenType* m_mat;
}; };

View File

@ -64,6 +64,10 @@ template<class T> // Tested with T = taucs_single or taucs_double
// May also work with T = taucs_dcomplex and taucs_scomplex // May also work with T = taucs_dcomplex and taucs_scomplex
class Taucs_symmetric_solver_traits class Taucs_symmetric_solver_traits
{ {
private:
boost::shared_ptr<taucs_io_handle> mtr;
// Public types // Public types
public: public:
@ -174,6 +178,104 @@ public:
} }
} }
bool pre_factor (const Matrix& A, NT& D)
{
D = 1; // TAUCS does not support homogeneous coordinates
#ifdef DEBUG_TRACE
// Turn on TAUCS trace to stderr or to a log file
#if DEBUG_TRACE >= 2
std::cerr.flush();
taucs_logfile((char*)"stderr");
#else
taucs_logfile((char*)"taucs.log");
#endif
#endif
#ifdef WIN32
Win32_exception_handler eh; // catch Win32 structured exceptions
#endif
try
{
int success;
// ordering
int* perm_raw = NULL;
int* invperm_raw = NULL;
taucs_ccs_order((taucs_ccs_matrix*) A.get_taucs_matrix(),
&perm_raw,
&invperm_raw,
(char*)"colamd");
boost::shared_ptr<int> perm(perm_raw, free);
boost::shared_ptr<int> invperm(invperm_raw, free);
if ( perm == NULL || invperm == NULL)
throw std::runtime_error("Ordering Failed");
// Create multi-file for out-of-core swapping.
// Note: g++ complains that tempnam() is deprecated. You may safely ignore the warning.
#ifdef _MSC_VER
char template_name[13] = {'t', 'a', 'u', 'c', 's','.','X','X','X','X','X','X', '\0' };
char* matrixfile = _mktemp(template_name);
if (matrixfile == NULL)
throw std::runtime_error("Cannot Create Multifile");
boost::shared_ptr<taucs_io_handle> oocL(taucs_io_create_multifile(matrixfile), taucs_io_delete);
mtr = oocL;
#else
boost::shared_ptr<char> matrixfile(tempnam(NULL, "taucs.L"), free);
if (matrixfile == NULL)
throw std::runtime_error("Cannot Create Multifile");
boost::shared_ptr<taucs_io_handle> oocL(taucs_io_create_multifile(matrixfile.get()), taucs_io_delete);
mtr = oocL;
#endif
if (mtr == NULL)
throw std::runtime_error("Cannot Create Multifile");
// factor
int memory_mb = int(taucs_available_memory_size()/1048576.0);
success = taucs_ooc_factor_llt((taucs_ccs_matrix*) A.get_taucs_matrix(),
mtr.get(),
memory_mb*1048576.0);
if (success != TAUCS_SUCCESS)
throw std::runtime_error("Factorization Failed");
return true;
}
catch (std::exception& e)
{
taucs_printf((char*)"\t");
taucs_printf((char*)(e.what() != NULL ? e.what() : "Incorrect Matrix"));
taucs_printf((char*)"\n");
return false;
}
catch (...)
{
taucs_printf((char*)"\tIncorrect Matrix\n");
return false;
}
}
bool solve (const Vector& B, Vector& X)
{
int success;
success = taucs_ooc_solve_llt(mtr.get(),
X.get_taucs_vector(),
(T*) B.get_taucs_vector());
if (success != TAUCS_SUCCESS)
throw std::runtime_error("Solving Failed");
return true;
}
private: private:
// Test if a floating point number is (close to) 0.0. // Test if a floating point number is (close to) 0.0.
@ -202,6 +304,11 @@ template<class T> // Tested with T = taucs_single or taucs_double
class Taucs_solver_traits class Taucs_solver_traits
{ {
// Public types // Public types
private:
boost::shared_ptr<taucs_io_handle> mtr;
public: public:
typedef Taucs_matrix<T> Matrix; typedef Taucs_matrix<T> Matrix;
@ -336,6 +443,105 @@ public:
} }
} }
bool pre_factor (const Matrix& A, NT& D)
{
D = 1; // TAUCS does not support homogeneous coordinates
#ifdef DEBUG_TRACE
// Turn on TAUCS trace to stderr or to a log file
#if DEBUG_TRACE >= 2
std::cerr.flush();
taucs_logfile((char*)"stderr");
#else
taucs_logfile((char*)"taucs.log");
#endif
#endif
#ifdef WIN32
Win32_exception_handler eh; // catch Win32 structured exceptions
#endif
try
{
int success;
// ordering
int* perm_raw = NULL;
int* invperm_raw = NULL;
taucs_ccs_order((taucs_ccs_matrix*) A.get_taucs_matrix(),
&perm_raw,
&invperm_raw,
(char*)"colamd");
boost::shared_ptr<int> perm(perm_raw, free);
boost::shared_ptr<int> invperm(invperm_raw, free);
if ( perm == NULL || invperm == NULL)
throw std::runtime_error("Ordering Failed");
// Create multi-file for out-of-core swapping.
// Note: g++ complains that tempnam() is deprecated. You may safely ignore the warning.
#ifdef _MSC_VER
char template_name[13] = {'t', 'a', 'u', 'c', 's','.','X','X','X','X','X','X', '\0' };
char* matrixfile = _mktemp(template_name);
if (matrixfile == NULL)
throw std::runtime_error("Cannot Create Multifile");
boost::shared_ptr<taucs_io_handle> oocL(taucs_io_create_multifile(matrixfile), taucs_io_delete);
mtr = oocL;
#else
boost::shared_ptr<char> matrixfile(tempnam(NULL, "taucs.L"), free);
if (matrixfile == NULL)
throw std::runtime_error("Cannot Create Multifile");
boost::shared_ptr<taucs_io_handle> oocL(taucs_io_create_multifile(matrixfile.get()), taucs_io_delete);
mtr = oocL;
#endif
if (mtr == NULL)
throw std::runtime_error("Cannot Create Multifile");
// factor
int memory_mb = int(taucs_available_memory_size()/1048576.0);
success = taucs_ooc_factor_lu((taucs_ccs_matrix*) A.get_taucs_matrix(),
perm.get(),
mtr.get(),
memory_mb*1048576.0);
if (success != TAUCS_SUCCESS)
throw std::runtime_error("Factorization Failed");
return true;
}
catch (std::exception& e)
{
taucs_printf((char*)"\t");
taucs_printf((char*)(e.what() != NULL ? e.what() : "Incorrect Matrix"));
taucs_printf((char*)"\n");
return false;
}
catch (...)
{
taucs_printf((char*)"\tIncorrect Matrix\n");
return false;
}
}
bool solve (const Vector& B, Vector& X)
{
int success;
success = taucs_ooc_solve_lu(mtr.get(),
X.get_taucs_vector(),
(T*) B.get_taucs_vector());
if (success != TAUCS_SUCCESS)
throw std::runtime_error("Solving Failed");
return true;
}
private: private:
// Test if a floating point number is (close to) 0.0. // Test if a floating point number is (close to) 0.0.

View File

@ -0,0 +1,45 @@
# Created by the script cgal_create_cmake_script
# This is the CMake script for compiling a CGAL application.
project( optimal_rotation_benchmark)
cmake_minimum_required(VERSION 2.6.2)
find_package(CGAL QUIET COMPONENTS Core )
if ( CGAL_FOUND )
add_definitions(-DDEBUG_TRACE)
include( ${CGAL_USE_FILE} )
add_executable ( optimal_rotation_svd_eigen
optimal_rotation_svd_eigen.cpp)
add_executable ( optimal_rotation_svd_nr
optimal_rotation_svd_nr.cpp
nrutil.cpp)
add_executable ( optimal_rotation_polar
optimal_rotation_polar.cpp)
add_executable ( optimal_rotation_polar_eigen
optimal_rotation_polar_eigen.cpp)
else()
message(STATUS "This program requires the CGAL library, and will not be compiled.")
endif()
find_package(Eigen3 3.0.0)
if(EIGEN3_FOUND)
include( ${EIGEN3_USE_FILE} )
endif(EIGEN3_FOUND)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,617 @@
#if 1
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#define NR_END 1
#define FREE_ARG char*
void nrerror(char error_text[])
/*Numerical Recipes standard error handler */
{
fprintf(stderr,"Numerical Recipes run-time error...\n");
fprintf(stderr,"%s\n",error_text);
fprintf(stderr,"...now exiting to system...\n");
exit(1);
}
float *vec(long nl, long nh)
/* allocate a float vector with subscript range v[nl..nh] */
{
float *v;
v=(float *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(float)));
if (!v) nrerror("allocation failure in vector()");
return v-nl+NR_END;
}
int *ivector(long nl, long nh)
/* allocate an int vector with subscript range v[nl..nh] */
{
int *v;
v=(int *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(int)));
if (!v) nrerror("allocation failure in ivector()");
return v-nl+NR_END;
}
unsigned char *cvector(long nl, long nh)
/* allocate an unsigned char vector with subscript range v[nl..nh] */
{
unsigned char *v;
v=(unsigned char *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(unsigned char)));
if (!v) nrerror("allocation failure in cvector()");
return v-nl+NR_END;
}
unsigned long *lvector(long nl, long nh)
/* allocate an unsigned long vector with subscript range v[nl..nh] */
{
unsigned long *v;
v=(unsigned long *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(long)));
if (!v) nrerror("allocation failure in lvector()");
return v-nl+NR_END;
}
double *dvector(long nl, long nh)
/* allocate a double vector with subscript range v[nl..nh] */
{
double *v;
v=(double *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(double)));
if (!v) nrerror("allocation failure in dvector()");
return v-nl+NR_END;
}
float **matrix(long nrl, long nrh, long ncl, long nch)
/* allocate a float matrix with subscript range m[nrl..nrh][ncl..nch] */
{
long i, nrow=nrh-nrl+1,ncol=nch-ncl+1;
float **m;
/* allocate pointers to rows */
m=(float **) malloc((size_t)((nrow+NR_END)*sizeof(float*)));
if (!m) nrerror("allocation failure 1 in matrix()");
m += NR_END;
m -= nrl;
/* allocate rows and set pointers to them */
m[nrl]=(float *) malloc((size_t)((nrow*ncol+NR_END)*sizeof(float)));
if (!m[nrl]) nrerror("allocation failure 2 in matrix()");
m[nrl] += NR_END;
m[nrl] -= ncl;
for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol;
/* return pointer to array of pointers to rows */
return m;
}
double **dmatrix(long nrl, long nrh, long ncl, long nch)
/* allocate a double matrix with subscript range m[nrl..nrh][ncl..nch] */
{
long i, nrow=nrh-nrl+1,ncol=nch-ncl+1;
double **m;
/* allocate pointers to rows */
m=(double **) malloc((size_t)((nrow+NR_END)*sizeof(double*)));
if (!m) nrerror("allocation failure 1 in matrix()");
m += NR_END;
m -= nrl;
/* allocate rows and set pointers to them */
m[nrl]=(double *) malloc((size_t)((nrow*ncol+NR_END)*sizeof(double)));
if (!m[nrl]) nrerror("allocation failure 2 in matrix()");
m[nrl] += NR_END;
m[nrl] -= ncl;
for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol;
/* return pointer to array of pointers to rows */
return m;
}
int **imatrix(long nrl, long nrh, long ncl, long nch)
/* allocate a int matrix with subscript range m[nrl..nrh][ncl..nch] */
{
long i, nrow=nrh-nrl+1,ncol=nch-ncl+1;
int **m;
/* allocate pointers to rows */
m=(int **) malloc((size_t)((nrow+NR_END)*sizeof(int*)));
if (!m) nrerror("allocation failure 1 in matrix()");
m += NR_END;
m -= nrl;
/* allocate rows and set pointers to them */
m[nrl]=(int *) malloc((size_t)((nrow*ncol+NR_END)*sizeof(int)));
if (!m[nrl]) nrerror("allocation failure 2 in matrix()");
m[nrl] += NR_END;
m[nrl] -= ncl;
for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol;
/* return pointer to array of pointers to rows */
return m;
}
float **submatrix(float **a, long oldrl, long oldrh, long oldcl, long oldch,
long newrl, long newcl)
/* point a submatrix [newrl..][newcl..] to a[oldrl..oldrh][oldcl..oldch] */
{
long i,j,nrow=oldrh-oldrl+1,ncol=oldcl-newcl;
float **m;
/* allocate array of pointers to rows */
m=(float **) malloc((size_t) ((nrow+NR_END)*sizeof(float*)));
if (!m) nrerror("allocation failure in submatrix()");
m += NR_END;
m -= newrl;
/* set pointers to rows */
for(i=oldrl,j=newrl;i<=oldrh;i++,j++) m[j]=a[i]+ncol;
/* return pointer to array of pointers to rows */
return m;
}
float **convert_matrix(float *a, long nrl, long nrh, long ncl, long nch)
/* allocate a float matrix m[nrl..nrh][ncl..nch] that points to the matrix
declared in the standard C manner as a[nrow][ncol], where nrow=nrh-nrl+1
and ncol=nch-ncl+1. The routine should be called with the address
&a[0][0] as the first argument. */
{
long i,j,nrow=nrh-nrl+1,ncol=nch-ncl+1;
float **m;
/* allocate pointers to rows */
m=(float **) malloc((size_t) ((nrow+NR_END)*sizeof(float*)));
if (!m) nrerror("allocation failure in convert_matrix()");
m += NR_END;
m -= nrl;
/* set pointers to rows */
m[nrl]=a-ncl;
for(i=1,j=nrl+1;i<nrow;i++,j++) m[j]=m[j-1]+ncol;
/* return pointer to array of pointers to rows */
return m;
}
float ***f3tensor(long nrl, long nrh, long ncl, long nch, long ndl, long ndh)
/* allocate a float 3tensor with range t[nrl..nrh][ncl..nch][ndl..ndh] */
{
long i,j,nrow=nrh-nrl+1,ncol=nch-ncl+1,ndep=ndh-ndl+1;
float ***t;
/* allocate pointers to pointers to rows */
t=(float ***) malloc((size_t)((nrow+NR_END)*sizeof(float**)));
if (!t) nrerror("allocation failure 1 in f3tensor()");
t += NR_END;
t -= nrl;
/* allocate pointers to rows and set pointers to them */
t[nrl]=(float **) malloc((size_t)((nrow*ncol+NR_END)*sizeof(float*)));
if (!t[nrl]) nrerror("allocation failure 2 in f3tensor()");
t[nrl] += NR_END;
t[nrl] -= ncl;
/* allocate rows and set pointers to them */
t[nrl][ncl]=(float *) malloc((size_t)((nrow*ncol*ndep+NR_END)*sizeof(float)));
if (!t[nrl][ncl]) nrerror("allocation failure 3 in f3tensor()");
t[nrl][ncl] += NR_END;
t[nrl][ncl] -= ndl;
for(j=ncl+1;j<=nch;j++) t[nrl][j]=t[nrl][j-1]+ndep;
for(i=nrl+1;i<=nrh;i++) {
t[i]=t[i-1]+ncol;
t[i][ncl]=t[i-1][ncl]+ncol*ndep;
for(j=ncl+1;j<=nch;j++) t[i][j]=t[i][j-1]+ndep;
}
/* return pointer to array of pointers to rows */
return t;
}
void free_vector(float *v, long nl, long nh)
/* free a float vector allocated with vector() */
{
free((FREE_ARG) (v+nl-NR_END));
}
void free_ivector(int *v, long nl, long nh)
/* free an int vector allocated with ivector() */
{
free((FREE_ARG) (v+nl-NR_END));
}
void free_cvector(unsigned char *v, long nl, long nh)
/* free an unsigned char vector allocated with cvector() */
{
free((FREE_ARG) (v+nl-NR_END));
}
void free_lvector(unsigned long *v, long nl, long nh)
/* free an unsigned long vector allocated with lvector() */
{
free((FREE_ARG) (v+nl-NR_END));
}
void free_dvector(double *v, long nl, long nh)
/* free a double vector allocated with dvector() */
{
free((FREE_ARG) (v+nl-NR_END));
}
void free_matrix(float **m, long nrl, long nrh, long ncl, long nch)
/* free a float matrix allocated by matrix() */
{
free((FREE_ARG) (m[nrl]+ncl-NR_END));
free((FREE_ARG) (m+nrl-NR_END));
}
void free_dmatrix(double **m, long nrl, long nrh, long ncl, long nch)
/* free a double matrix allocated by dmatrix() */
{
free((FREE_ARG) (m[nrl]+ncl-NR_END));
free((FREE_ARG) (m+nrl-NR_END));
}
void free_imatrix(int **m, long nrl, long nrh, long ncl, long nch)
/* free an int matrix allocated by imatrix() */
{
free((FREE_ARG) (m[nrl]+ncl-NR_END));
free((FREE_ARG) (m+nrl-NR_END));
}
void free_submatrix(float **b, long nrl, long nrh, long ncl, long nch)
/* free a submatrix allocated by submatrix() */
{
free((FREE_ARG) (b+nrl-NR_END));
}
void free_convert_matrix(float **b, long nrl, long nrh, long ncl, long nch)
/* free a matrix allocated by convert_matrix() */
{
free((FREE_ARG) (b+nrl-NR_END));
}
void free_f3tensor(float ***t, long nrl, long nrh, long ncl, long nch,
long ndl, long ndh)
/* free a float f3tensor allocated by f3tensor() */
{
free((FREE_ARG) (t[nrl][ncl]+ndl-NR_END));
free((FREE_ARG) (t[nrl]+ncl-NR_END));
free((FREE_ARG) (t+nrl-NR_END));
}
#else /* ANSI */
/* traditional - K&R */
#include <stdio.h>
#define NR_END 1
#define FREE_ARG char*
void nrerror(error_text)
char error_text[];
/* Numerical Recipes standard error handler */
{
void exit();
fprintf(stderr,"Numerical Recipes run-time error...\n");
fprintf(stderr,"%s\n",error_text);
fprintf(stderr,"...now exiting to system...\n");
exit(1);
}
float *vector(nl,nh)
long nh,nl;
/* allocate a float vector with subscript range v[nl..nh] */
{
float *v;
v=(float *)malloc((unsigned int) ((nh-nl+1+NR_END)*sizeof(float)));
if (!v) nrerror("allocation failure in vector()");
return v-nl+NR_END;
}
int *ivector(nl,nh)
long nh,nl;
/* allocate an int vector with subscript range v[nl..nh] */
{
int *v;
v=(int *)malloc((unsigned int) ((nh-nl+1+NR_END)*sizeof(int)));
if (!v) nrerror("allocation failure in ivector()");
return v-nl+NR_END;
}
unsigned char *cvector(nl,nh)
long nh,nl;
/* allocate an unsigned char vector with subscript range v[nl..nh] */
{
unsigned char *v;
v=(unsigned char *)malloc((unsigned int) ((nh-nl+1+NR_END)*sizeof(unsigned char)));
if (!v) nrerror("allocation failure in cvector()");
return v-nl+NR_END;
}
unsigned long *lvector(nl,nh)
long nh,nl;
/* allocate an unsigned long vector with subscript range v[nl..nh] */
{
unsigned long *v;
v=(unsigned long *)malloc((unsigned int) ((nh-nl+1+NR_END)*sizeof(long)));
if (!v) nrerror("allocation failure in lvector()");
return v-nl+NR_END;
}
double *dvector(nl,nh)
long nh,nl;
/* allocate a double vector with subscript range v[nl..nh] */
{
double *v;
v=(double *)malloc((unsigned int) ((nh-nl+1+NR_END)*sizeof(double)));
if (!v) nrerror("allocation failure in dvector()");
return v-nl+NR_END;
}
float **matrix(nrl,nrh,ncl,nch)
long nch,ncl,nrh,nrl;
/* allocate a float matrix with subscript range m[nrl..nrh][ncl..nch] */
{
long i, nrow=nrh-nrl+1,ncol=nch-ncl+1;
float **m;
/* allocate pointers to rows */
m=(float **) malloc((unsigned int)((nrow+NR_END)*sizeof(float*)));
if (!m) nrerror("allocation failure 1 in matrix()");
m += NR_END;
m -= nrl;
/* allocate rows and set pointers to them */
m[nrl]=(float *) malloc((unsigned int)((nrow*ncol+NR_END)*sizeof(float)));
if (!m[nrl]) nrerror("allocation failure 2 in matrix()");
m[nrl] += NR_END;
m[nrl] -= ncl;
for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol;
/* return pointer to array of pointers to rows */
return m;
}
double **dmatrix(nrl,nrh,ncl,nch)
long nch,ncl,nrh,nrl;
/* allocate a double matrix with subscript range m[nrl..nrh][ncl..nch] */
{
long i, nrow=nrh-nrl+1,ncol=nch-ncl+1;
double **m;
/* allocate pointers to rows */
m=(double **) malloc((unsigned int)((nrow+NR_END)*sizeof(double*)));
if (!m) nrerror("allocation failure 1 in matrix()");
m += NR_END;
m -= nrl;
/* allocate rows and set pointers to them */
m[nrl]=(double *) malloc((unsigned int)((nrow*ncol+NR_END)*sizeof(double)));
if (!m[nrl]) nrerror("allocation failure 2 in matrix()");
m[nrl] += NR_END;
m[nrl] -= ncl;
for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol;
/* return pointer to array of pointers to rows */
return m;
}
int **imatrix(nrl,nrh,ncl,nch)
long nch,ncl,nrh,nrl;
/* allocate a int matrix with subscript range m[nrl..nrh][ncl..nch] */
{
long i, nrow=nrh-nrl+1,ncol=nch-ncl+1;
int **m;
/* allocate pointers to rows */
m=(int **) malloc((unsigned int)((nrow+NR_END)*sizeof(int*)));
if (!m) nrerror("allocation failure 1 in matrix()");
m += NR_END;
m -= nrl;
/* allocate rows and set pointers to them */
m[nrl]=(int *) malloc((unsigned int)((nrow*ncol+NR_END)*sizeof(int)));
if (!m[nrl]) nrerror("allocation failure 2 in matrix()");
m[nrl] += NR_END;
m[nrl] -= ncl;
for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol;
/* return pointer to array of pointers to rows */
return m;
}
float **submatrix(a,oldrl,oldrh,oldcl,oldch,newrl,newcl)
float **a;
long newcl,newrl,oldch,oldcl,oldrh,oldrl;
/* point a submatrix [newrl..][newcl..] to a[oldrl..oldrh][oldcl..oldch] */
{
long i,j,nrow=oldrh-oldrl+1,ncol=oldcl-newcl;
float **m;
/* allocate array of pointers to rows */
m=(float **) malloc((unsigned int) ((nrow+NR_END)*sizeof(float*)));
if (!m) nrerror("allocation failure in submatrix()");
m += NR_END;
m -= newrl;
/* set pointers to rows */
for(i=oldrl,j=newrl;i<=oldrh;i++,j++) m[j]=a[i]+ncol;
/* return pointer to array of pointers to rows */
return m;
}
float **convert_matrix(a,nrl,nrh,ncl,nch)
float *a;
long nch,ncl,nrh,nrl;
/* allocate a float matrix m[nrl..nrh][ncl..nch] that points to the matrix
declared in the standard C manner as a[nrow][ncol], where nrow=nrh-nrl+1
and ncol=nch-ncl+1. The routine should be called with the address
&a[0][0] as the first argument. */
{
long i,j,nrow=nrh-nrl+1,ncol=nch-ncl+1;
float **m;
/* allocate pointers to rows */
m=(float **) malloc((unsigned int) ((nrow+NR_END)*sizeof(float*)));
if (!m) nrerror("allocation failure in convert_matrix()");
m += NR_END;
m -= nrl;
/* set pointers to rows */
m[nrl]=a-ncl;
for(i=1,j=nrl+1;i<nrow;i++,j++) m[j]=m[j-1]+ncol;
/* return pointer to array of pointers to rows */
return m;
}
float ***f3tensor(nrl,nrh,ncl,nch,ndl,ndh)
long nch,ncl,ndh,ndl,nrh,nrl;
/* allocate a float 3tensor with range t[nrl..nrh][ncl..nch][ndl..ndh] */
{
long i,j,nrow=nrh-nrl+1,ncol=nch-ncl+1,ndep=ndh-ndl+1;
float ***t;
/* allocate pointers to pointers to rows */
t=(float ***) malloc((unsigned int)((nrow+NR_END)*sizeof(float**)));
if (!t) nrerror("allocation failure 1 in f3tensor()");
t += NR_END;
t -= nrl;
/* allocate pointers to rows and set pointers to them */
t[nrl]=(float **) malloc((unsigned int)((nrow*ncol+NR_END)*sizeof(float*)));
if (!t[nrl]) nrerror("allocation failure 2 in f3tensor()");
t[nrl] += NR_END;
t[nrl] -= ncl;
/* allocate rows and set pointers to them */
t[nrl][ncl]=(float *) malloc((unsigned int)((nrow*ncol*ndep+NR_END)*sizeof(float)));
if (!t[nrl][ncl]) nrerror("allocation failure 3 in f3tensor()");
t[nrl][ncl] += NR_END;
t[nrl][ncl] -= ndl;
for(j=ncl+1;j<=nch;j++) t[nrl][j]=t[nrl][j-1]+ndep;
for(i=nrl+1;i<=nrh;i++) {
t[i]=t[i-1]+ncol;
t[i][ncl]=t[i-1][ncl]+ncol*ndep;
for(j=ncl+1;j<=nch;j++) t[i][j]=t[i][j-1]+ndep;
}
/* return pointer to array of pointers to rows */
return t;
}
void free_vector(v,nl,nh)
float *v;
long nh,nl;
/* free a float vector allocated with vector() */
{
free((FREE_ARG) (v+nl-NR_END));
}
void free_ivector(v,nl,nh)
int *v;
long nh,nl;
/* free an int vector allocated with ivector() */
{
free((FREE_ARG) (v+nl-NR_END));
}
void free_cvector(v,nl,nh)
long nh,nl;
unsigned char *v;
/* free an unsigned char vector allocated with cvector() */
{
free((FREE_ARG) (v+nl-NR_END));
}
void free_lvector(v,nl,nh)
long nh,nl;
unsigned long *v;
/* free an unsigned long vector allocated with lvector() */
{
free((FREE_ARG) (v+nl-NR_END));
}
void free_dvector(v,nl,nh)
double *v;
long nh,nl;
/* free a double vector allocated with dvector() */
{
free((FREE_ARG) (v+nl-NR_END));
}
void free_matrix(m,nrl,nrh,ncl,nch)
float **m;
long nch,ncl,nrh,nrl;
/* free a float matrix allocated by matrix() */
{
free((FREE_ARG) (m[nrl]+ncl-NR_END));
free((FREE_ARG) (m+nrl-NR_END));
}
void free_dmatrix(m,nrl,nrh,ncl,nch)
double **m;
long nch,ncl,nrh,nrl;
/* free a double matrix allocated by dmatrix() */
{
free((FREE_ARG) (m[nrl]+ncl-NR_END));
free((FREE_ARG) (m+nrl-NR_END));
}
void free_imatrix(m,nrl,nrh,ncl,nch)
int **m;
long nch,ncl,nrh,nrl;
/* free an int matrix allocated by imatrix() */
{
free((FREE_ARG) (m[nrl]+ncl-NR_END));
free((FREE_ARG) (m+nrl-NR_END));
}
void free_submatrix(b,nrl,nrh,ncl,nch)
float **b;
long nch,ncl,nrh,nrl;
/* free a submatrix allocated by submatrix() */
{
free((FREE_ARG) (b+nrl-NR_END));
}
void free_convert_matrix(b,nrl,nrh,ncl,nch)
float **b;
long nch,ncl,nrh,nrl;
/* free a matrix allocated by convert_matrix() */
{
free((FREE_ARG) (b+nrl-NR_END));
}
void free_f3tensor(t,nrl,nrh,ncl,nch,ndl,ndh)
float ***t;
long nch,ncl,ndh,ndl,nrh,nrl;
/* free a float f3tensor allocated by f3tensor() */
{
free((FREE_ARG) (t[nrl][ncl]+ndl-NR_END));
free((FREE_ARG) (t[nrl]+ncl-NR_END));
free((FREE_ARG) (t+nrl-NR_END));
}
#endif /* ANSI */

View File

@ -0,0 +1,101 @@
#ifndef _NR_UTILS_H_
#define _NR_UTILS_H_
static float sqrarg;
#define SQR(a) ((sqrarg=(a)) == 0.0 ? 0.0 : sqrarg*sqrarg)
static double dsqrarg;
#define DSQR(a) ((dsqrarg=(a)) == 0.0 ? 0.0 : dsqrarg*dsqrarg)
static double dmaxarg1,dmaxarg2;
#define DMAX(a,b) (dmaxarg1=(a),dmaxarg2=(b),(dmaxarg1) > (dmaxarg2) ?\
(dmaxarg1) : (dmaxarg2))
static double dminarg1,dminarg2;
#define DMIN(a,b) (dminarg1=(a),dminarg2=(b),(dminarg1) < (dminarg2) ?\
(dminarg1) : (dminarg2))
static float maxarg1,maxarg2;
#define FMAX(a,b) (maxarg1=(a),maxarg2=(b),(maxarg1) > (maxarg2) ?\
(maxarg1) : (maxarg2))
static float minarg1,minarg2;
#define FMIN(a,b) (minarg1=(a),minarg2=(b),(minarg1) < (minarg2) ?\
(minarg1) : (minarg2))
static long lmaxarg1,lmaxarg2;
#define LMAX(a,b) (lmaxarg1=(a),lmaxarg2=(b),(lmaxarg1) > (lmaxarg2) ?\
(lmaxarg1) : (lmaxarg2))
static long lminarg1,lminarg2;
#define LMIN(a,b) (lminarg1=(a),lminarg2=(b),(lminarg1) < (lminarg2) ?\
(lminarg1) : (lminarg2))
static int imaxarg1,imaxarg2;
#define IMAX(a,b) (imaxarg1=(a),imaxarg2=(b),(imaxarg1) > (imaxarg2) ?\
(imaxarg1) : (imaxarg2))
static int iminarg1,iminarg2;
#define IMIN(a,b) (iminarg1=(a),iminarg2=(b),(iminarg1) < (iminarg2) ?\
(iminarg1) : (iminarg2))
#define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
#if 1
void nrerror(char error_text[]);
float *vec(long nl, long nh);
int *ivector(long nl, long nh);
unsigned char *cvector(long nl, long nh);
unsigned long *lvector(long nl, long nh);
double *dvector(long nl, long nh);
float **matrix(long nrl, long nrh, long ncl, long nch);
double **dmatrix(long nrl, long nrh, long ncl, long nch);
int **imatrix(long nrl, long nrh, long ncl, long nch);
float **submatrix(float **a, long oldrl, long oldrh, long oldcl, long oldch,
long newrl, long newcl);
float **convert_matrix(float *a, long nrl, long nrh, long ncl, long nch);
float ***f3tensor(long nrl, long nrh, long ncl, long nch, long ndl, long ndh);
void free_vector(float *v, long nl, long nh);
void free_ivector(int *v, long nl, long nh);
void free_cvector(unsigned char *v, long nl, long nh);
void free_lvector(unsigned long *v, long nl, long nh);
void free_dvector(double *v, long nl, long nh);
void free_matrix(float **m, long nrl, long nrh, long ncl, long nch);
void free_dmatrix(double **m, long nrl, long nrh, long ncl, long nch);
void free_imatrix(int **m, long nrl, long nrh, long ncl, long nch);
void free_submatrix(float **b, long nrl, long nrh, long ncl, long nch);
void free_convert_matrix(float **b, long nrl, long nrh, long ncl, long nch);
void free_f3tensor(float ***t, long nrl, long nrh, long ncl, long nch,
long ndl, long ndh);
#else /* ANSI */
/* traditional - K&R */
void nrerror();
float *vec();
float **matrix();
float **submatrix();
float **convert_matrix();
float ***f3tensor();
double *dvector();
double **dmatrix();
int *ivector();
int **imatrix();
unsigned char *cvector();
unsigned long *lvector();
void free_vector();
void free_dvector();
void free_ivector();
void free_cvector();
void free_lvector();
void free_matrix();
void free_submatrix();
void free_convert_matrix();
void free_dmatrix();
void free_imatrix();
void free_f3tensor();
#endif /* ANSI */
#endif /* _NR_UTILS_H_ */

View File

@ -0,0 +1,113 @@
#include <CGAL/trace.h>
#include <CGAL/Timer.h>
#include <iostream>
#include <string>
#include <fstream>
#include <Eigen/Eigen>
#include <Eigen/SVD>
double norm_1(Eigen::Matrix3d X)
{
double sum = 0;
for ( int i = 0; i < 3; i++ )
{
for ( int j = 0; j < 3; j++ )
{
sum += abs(X(i,j));
}
}
return sum;
}
double norm_inf(Eigen::Matrix3d X)
{
double max_abs = abs(X(0,0));
for ( int i = 0; i < 3; i++ )
{
for ( int j = 0; j < 3; j++ )
{
double new_abs = abs(X(i,j));
if ( new_abs > max_abs )
{
max_abs = new_abs;
}
}
}
return max_abs;
}
void algorithm_polar(Eigen::Matrix3d A, Eigen::Matrix3d &U, double tolerance)
{
Eigen::Matrix3d X = A;
int k = -1;
Eigen::Matrix3d Y;
double alpha, beta, gamma;
do
{
k++;
Y = X.inverse();
alpha = sqrt( norm_1(X) * norm_inf(X) );
beta = sqrt( norm_1(Y) * norm_inf(Y) );
gamma = sqrt(beta/alpha);
X = 0.5*( gamma*X + Y.transpose()/gamma );
} while ( abs(gamma-1) > tolerance );
U = X;
}
int main() {
std::ifstream file;
file.open("SVD_benchmark");
if (!file)
{
CGAL_TRACE_STREAM << "Error loading file!\n";
return 0;
}
int ite = 200000;
Eigen::Matrix3d A, U, H;
int matrix_idx = rand()%200;
for (int i = 0; i < matrix_idx; i++)
{
for (int j = 0; j < 3; j++)
{
for (int k = 0; k < 3; k++)
{
file >> A(j, k);
}
}
}
file.close();
A(0,0) = 0.0014667022958104185; A(0,1) = 0.0024644551180079627; A(0,2) = 0.0040659871060825092;
A(1,0) = 0.0028327558016991478; A(1,1) = 0.0054236820249146406; A(1,2) = 0.0079280090866983826;
A(2,0) = 0.0039090073251031232; A(2,1) = 0.0066744523074963374; A(2,2) = 0.010848552426718550;
A = A*10000;
CGAL::Timer task_timer;
CGAL_TRACE_STREAM << "Start SVD decomposition...";
task_timer.start();
for (int i = 0; i < ite; i++)
{
algorithm_polar(A, U, 1e-6);
U.transposeInPlace();
double det_2 = U.determinant();
int aaa = 0;
}
task_timer.stop();
CGAL_TRACE_STREAM << "done: " << task_timer.time() << "s\n";
return 0;
}

View File

@ -0,0 +1,162 @@
#include <CGAL/trace.h>
#include <CGAL/Timer.h>
#include <iostream>
#include <string>
#include <fstream>
#include <CGAL/FPU_extension.h>
#include <Eigen/Eigen>
#include <Eigen/SVD>
double norm_1(Eigen::Matrix3d X)
{
double sum = 0;
for ( int i = 0; i < 3; i++ )
{
for ( int j = 0; j < 3; j++ )
{
sum += abs(X(i,j));
}
}
return sum;
}
double norm_inf(Eigen::Matrix3d X)
{
double max_abs = abs(X(0,0));
for ( int i = 0; i < 3; i++ )
{
for ( int j = 0; j < 3; j++ )
{
double new_abs = abs(X(i,j));
if ( new_abs > max_abs )
{
max_abs = new_abs;
}
}
}
return max_abs;
}
template<typename Mat>
void polar_eigen(const Mat& A, Mat& R, bool& SVD)
{
typedef typename Mat::Scalar Scalar;
typedef Eigen::Matrix<typename Mat::Scalar,3,1> Vec;
const Scalar th = std::sqrt(Eigen::NumTraits<Scalar>::dummy_precision());
Eigen::SelfAdjointEigenSolver<Mat> eig;
feclearexcept(FE_UNDERFLOW);
eig.computeDirect(A.transpose()*A);
if(fetestexcept(FE_UNDERFLOW) || eig.eigenvalues()(0)/eig.eigenvalues()(2)/100.0<th)
{
// The computation of the eigenvalues might have diverged.
// Fallback to an accurate SVD based decomposiiton method.
Eigen::JacobiSVD<Mat> svd;
svd.compute(A, Eigen::ComputeFullU | Eigen::ComputeFullV );
const Mat& u = svd.matrixU(); const Mat& v = svd.matrixV(); const Vec& w = svd.singularValues();
R = u*v.transpose();
SVD = true;
return;
}
Vec S = eig.eigenvalues().cwiseSqrt();
R = A * eig.eigenvectors() * S.asDiagonal().inverse()
* eig.eigenvectors().transpose();
SVD = false;
}
int main() {
std::ifstream file;
file.open("Polar_benchmark");
if (!file)
{
CGAL_TRACE_STREAM << "Error loading file!\n";
return 0;
}
Eigen::Matrix3d A, U, r;
bool SVD = false;
int num_svd = 0;
int num_mtr = 0;
CGAL_TRACE_STREAM << "start polar decomposition...\n";
while (!file.eof())
{
for (int j = 0; j < 3; j++)
{
for (int k = 0; k < 3; k++)
{
file >> A(j, k);
}
}
num_mtr++;
double det = A.determinant();
if (A.determinant() > 0)
{
polar_eigen<Eigen::Matrix3d> (A, U, SVD);
if (SVD)
num_svd++;
U.transposeInPlace();
double det_2 = U.determinant();
if ( abs(det_2-1) > 1e-2 )
{
CGAL_TRACE_STREAM << "error matrix: det = " << det_2 << "\n";
}
}
}
file.close();
CGAL_TRACE_STREAM << "done. " << num_svd << " SVD decompositions in " << num_mtr << " matrices\n";
return 0;
/*int ite = 200000;
Eigen::JacobiSVD<Eigen::Matrix3d> svd;
Eigen::Matrix3d A, U, H, r;
int matrix_idx = rand()%200;
for (int i = 0; i < matrix_idx; i++)
{
for (int j = 0; j < 3; j++)
{
for (int k = 0; k < 3; k++)
{
file >> A(j, k);
}
}
}
file.close();
A(0,0) = 0.0014667022958104185; A(0,1) = 0.0024644551180079627; A(0,2) = 0.0040659871060825092;
A(1,0) = 0.0028327558016991478; A(1,1) = 0.0054236820249146406; A(1,2) = 0.0079280090866983826;
A(2,0) = 0.0039090073251031232; A(2,1) = 0.0066744523074963374; A(2,2) = 0.010848552426718550;
A = A*10000;
double det = A.determinant();
CGAL::Timer task_timer;
CGAL_TRACE_STREAM << "Start SVD decomposition...";
task_timer.start();
for (int i = 0; i < ite; i++)
{
if (A.determinant() > 0)
{
polar_eigen<Eigen::Matrix3d> (A, U);
U.transposeInPlace();
double det_2 = U.determinant();
r = U*U.transpose();
}
}
task_timer.stop();
CGAL_TRACE_STREAM << "done: " << task_timer.time() << "s\n";
return 0;*/
}

View File

@ -0,0 +1,57 @@
#include <CGAL/trace.h>
#include <CGAL/Timer.h>
#include <iostream>
#include <string>
#include <fstream>
#include <Eigen/Eigen>
#include <Eigen/SVD>
int main() {
std::ifstream file;
file.open("SVD_benchmark");
if (!file)
{
CGAL_TRACE_STREAM << "Error loading file!\n";
return 0;
}
int ite = 200000;
Eigen::JacobiSVD<Eigen::Matrix3d> svd;
Eigen::Matrix3d u, v, cov, r;
Eigen::Vector3d w;
int matrix_idx = rand()%200;
for (int i = 0; i < matrix_idx; i++)
{
for (int j = 0; j < 3; j++)
{
for (int k = 0; k < 3; k++)
{
file >> cov(j, k);
}
}
}
CGAL::Timer task_timer;
CGAL_TRACE_STREAM << "Start SVD decomposition...";
task_timer.start();
for (int i = 0; i < ite; i++)
{
svd.compute( cov, Eigen::ComputeFullU | Eigen::ComputeFullV );
u = svd.matrixU(); v = svd.matrixV(); w = svd.singularValues();
r = v*u.transpose();
}
task_timer.stop();
file.close();
CGAL_TRACE_STREAM << "done: " << task_timer.time() << "s\n";
return 0;
}

View File

@ -0,0 +1,91 @@
#include "svd.h"
#include <CGAL/trace.h>
#include <CGAL/Timer.h>
#include <iostream>
#include <string>
#include <fstream>
int main() {
std::ifstream file;
file.open("SVD_benchmark");
if (!file)
{
CGAL_TRACE_STREAM << "Error loading file!\n";
return 0;
}
// initialization of matrices
int ite = 200000;
double ***u;
u = new double** [ite];
for (int i = 0; i < ite; i++)
{
u[i] = new double* [4];
for (int j = 0; j < 4; j++)
{
u[i][j] = new double [4];
}
}
int matrix_idx = rand()%200;
for (int i = 0; i < matrix_idx; i++)
{
for (int j = 0; j < 3; j++)
{
for (int k = 0; k < 3; k++)
{
file >> u[0][j+1][k+1];
}
}
}
for (int i = 1; i < ite; i++)
{
for (int j = 0; j < 3; j++)
{
for (int k = 0; k < 3; k++)
{
u[i][j+1][k+1] = u[0][j+1][k+1];
}
}
}
double **v;
v = new double* [4];
for (int i = 0; i < 4; i++)
{
v[i] = new double[4];
}
double *w;
w = new double[4];
CGAL::Timer task_timer;
CGAL_TRACE_STREAM << "Start SVD decomposition...";
task_timer.start();
for (int i = 0; i < ite; i++)
{
svdcmp(u[i], 3, 3, w, v);
}
task_timer.stop();
file.close();
CGAL_TRACE_STREAM << "done: " << task_timer.time() << "s\n";
delete [] w;
for (int i = 0; i < 4; i++)
{
delete [] v[i];
}
delete [] v;
for (int i = 0; i < ite; i++)
{
for (int j = 0; j < 4; j++)
{
delete [] u[i][j];
}
delete [] u[i];
}
delete [] u;
return 0;
}

View File

@ -0,0 +1,209 @@
#pragma once
#include <math.h>
#include "nrutil.h"
double pythag(double a, double b);
inline void svdcmp(double **a, int m, int n, double w[], double **v)
{
double pythag(double a, double b);
int flag,i,its,j,jj,k,l,nm;
double anorm,c,f,g,h,s,scale,x,y,z,*rv1;
rv1=dvector(1,n);
g=scale=anorm=0.0; //Householder reduction to bidiagonal form.
for (i=1;i<=n;i++) {
l=i+1;
rv1[i]=scale*g;
g=s=scale=0.0;
if (i <= m) {
for (k=i;k<=m;k++) scale += fabs(a[k][i]);
if (scale) {
for (k=i;k<=m;k++) {
a[k][i] /= scale;
s += a[k][i]*a[k][i];
}
f=a[i][i];
g = -SIGN(sqrt(s),f);
h=f*g-s;
a[i][i]=f-g;
for (j=l;j<=n;j++) {
for (s=0.0,k=i;k<=m;k++) s += a[k][i]*a[k][j];
f=s/h;
for (k=i;k<=m;k++) a[k][j] += f*a[k][i];
}
for (k=i;k<=m;k++) a[k][i] *= scale;
}
}
w[i]=scale *g;
g=s=scale=0.0;
if (i <= m && i != n) {
for (k=l;k<=n;k++) scale += fabs(a[i][k]);
if (scale) {
for (k=l;k<=n;k++) {
a[i][k] /= scale;
s += a[i][k]*a[i][k];
}
f=a[i][l];
g = -SIGN(sqrt(s),f);
h=f*g-s;
a[i][l]=f-g;
for (k=l;k<=n;k++) rv1[k]=a[i][k]/h;
for (j=l;j<=m;j++) {
for (s=0.0,k=l;k<=n;k++) s += a[j][k]*a[i][k];
for (k=l;k<=n;k++) a[j][k] += s*rv1[k];
}
for (k=l;k<=n;k++) a[i][k] *= scale;
}
}
anorm=DMAX(anorm,(fabs(w[i])+fabs(rv1[i])));
}
for (i=n;i>=1;i--) { //Accumulation of right-hand transformations.
if (i < n) {
if (g) {
for (j=l;j<=n;j++) //Double division to avoid possible underflow.
v[j][i]=(a[i][j]/a[i][l])/g;
for (j=l;j<=n;j++) {
for (s=0.0,k=l;k<=n;k++) s += a[i][k]*v[k][j];
for (k=l;k<=n;k++) v[k][j] += s*v[k][i];
}
}
for (j=l;j<=n;j++) v[i][j]=v[j][i]=0.0;
}
v[i][i]=1.0;
g=rv1[i];
l=i;
}
for (i=IMIN(m,n);i>=1;i--) { //Accumulation of left-hand transformations.
l=i+1;
g=w[i];
for (j=l;j<=n;j++) a[i][j]=0.0;
if (g) {
g=1.0/g;
for (j=l;j<=n;j++) {
for (s=0.0,k=l;k<=m;k++) s += a[k][i]*a[k][j];
f=(s/a[i][i])*g;
for (k=i;k<=m;k++) a[k][j] += f*a[k][i];
}
for (j=i;j<=m;j++) a[j][i] *= g;
} else for (j=i;j<=m;j++) a[j][i]=0.0;
++a[i][i];
}
for (k=n;k>=1;k--)
{ //Diagonalization of the bidiagonal form: Loop over
for (its=1;its<=30;its++)
{
flag=1;
for (l=k;l>=1;l--)
{ //Test for splitting.
nm=l-1; //Note that rv1[1] is always zero.
if ((double)(fabs(rv1[l])+anorm) == anorm)
{
flag=0;
break;
}
if ((double)(fabs(w[nm])+anorm) == anorm) break;
}
if (flag)
{
c=0.0; //Cancellation of rv1[l], if l > 1.
s=1.0;
for (i=l;i<=k;i++)
{
f=s*rv1[i];
rv1[i]=c*rv1[i];
if ((double)(fabs(f)+anorm) == anorm)
break;
g=w[i];
h=pythag(f,g);
w[i]=h;
h=1.0/h;
c=g*h;
s = -f*h;
for (j=1;j<=m;j++)
{
y=a[j][nm];
z=a[j][i];
a[j][nm]=y*c+z*s;
a[j][i]=z*c-y*s;
}
}
}
z=w[k];
if (l == k)
{ //Convergence.
if (z < 0.0)
{ //Singular value is made nonnegative.
w[k] = -z;
for (j=1;j<=n;j++)
v[j][k] = -v[j][k];
}
break;
}
/* if (its == 30)
nrerror("no convergence in 30 svdcmp iterations");*/
x=w[l]; //Shift from bottom 2-by-2 minor.
nm=k-1;
y=w[nm];
g=rv1[nm];
h=rv1[k];
f=((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y);
g=pythag(f,1.0);
f=((x-z)*(x+z)+h*((y/(f+SIGN(g,f)))-h))/x;
c=s=1.0; //Next QR transformation:
for (j=l;j<=nm;j++)
{
i=j+1;
g=rv1[i];
y=w[i];
h=s*g;
g=c*g;
z=pythag(f,h);
rv1[j]=z;
c=f/z;
s=h/z;
f=x*c+g*s;
g = g*c-x*s;
h=y*s;
y *= c;
for (jj=1;jj<=n;jj++)
{
x=v[jj][j];
z=v[jj][i];
v[jj][j]=x*c+z*s;
v[jj][i]=z*c-x*s;
}
z=pythag(f,h);
w[j]=z; //Rotation can be arbitrary if z = 0.
if (z)
{
z=1.0/z;
c=f*z;
s=h*z;
}
f=c*g+s*y;
x=c*y-s*g;
for (jj=1;jj<=m;jj++)
{
y=a[jj][j];
z=a[jj][i];
a[jj][j]=y*c+z*s;
a[jj][i]=z*c-y*s;
}
}
rv1[l]=0.0;
rv1[k]=f;
w[k]=x;
}
}
free_dvector(rv1,1,n);
}
inline double pythag(double a, double b)
{
double absa,absb;
absa=fabs(a);
absb=fabs(b);
if (absa > absb) return absa*sqrt(1.0+DSQR(absb/absa));
else return (absb == 0.0 ? 0.0 : absb*sqrt(1.0+DSQR(absa/absb)));
}

View File

@ -0,0 +1,29 @@
# Created by the script cgal_create_cmake_script
# This is the CMake script for compiling a CGAL application.
project( Surface_modeling_example )
cmake_minimum_required(VERSION 2.6.2)
find_package(CGAL QUIET COMPONENTS Core )
if ( CGAL_FOUND )
include( ${CGAL_USE_FILE} )
include( CGAL_CreateSingleSourceCGALProgram )
include_directories (BEFORE ../../include)
create_single_source_cgal_program( "hello.cpp" )
create_single_source_cgal_program( "k-ring.cpp" )
create_single_source_cgal_program( "k-ring_BGL.cpp" )
create_single_source_cgal_program( "example.cpp" )
else()
message(STATUS "This program requires the CGAL library, and will not be compiled.")
endif()

View File

@ -0,0 +1,55 @@
#include <CGAL/Polyhedron_items_with_id_3.h>
#include <CGAL/Taucs_solver_traits.h>
#include <CGAL/Deform_mesh_BGL.h>
typedef CGAL::Cartesian<double> Kernel;
typedef Kernel::Vector_3 Vector;
typedef CGAL::Polyhedron_3<Kernel,CGAL::Polyhedron_items_with_id_3> Polyhedron;
typedef CGAL::Deform_mesh_BGL<Polyhedron, CGAL::Taucs_solver_traits<double> > Deform_mesh;
typedef boost::graph_traits<Polyhedron>::vertex_iterator vertex_iterator;
typedef Polyhedron::Vertex_handle Vertex_handle;
int main() {
// read an off file
Polyhedron P; //source mesh
std::cout << "Please input filename: ";
std::string filename;
std::cin >> filename;
std::string fullname = filename + ".off";
std::ifstream input(&fullname[0]);
input >> P;
std::cout << P.size_of_vertices() << " vertices; " << P.size_of_facets() << "facets" << std::endl;
input.close();
Deform_mesh deform(P);
vertex_iterator vb, ve;
boost::tie(vb,ve) = boost::vertices(P);
Vertex_handle vv = P.vertices_begin();
// takes arbitrary vertex as handle
deform.handles(vv, vv);
// determine the k-ring
deform.region_of_interest(vv, vv, 1);
// does the precomputation
deform.preprocess();
// displaces the handle by the Vector_3 v - origin
Vector translation = (vv)->point() - CGAL::ORIGIN;
deform(vv, translation);
// write the polyhedron to a file
std::string outname = filename + "_arap.off";
std::cout << "output to " << outname << "...";
std::ofstream output(&outname[0]);
output << deform.polyhedron;
output.close();
std::cout << "done." << std::endl;
output.close();
return 0;
}

View File

@ -0,0 +1,128 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Polyhedron_incremental_builder_3.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <iostream>
#include <string>
#include <fstream>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef CGAL::Polyhedron_3<Kernel> Polyhedron;
typedef Polyhedron::HalfedgeDS HalfedgeDS;
typedef Polyhedron::Vertex_const_handle Vertex_handle;
typedef Polyhedron::Halfedge_around_vertex_const_circulator HV_circulator;
using namespace std;
// A modifier creating a triangle with the incremental builder.
template <class HDS>
class Build_triangle : public CGAL::Modifier_base<HDS> {
public:
Build_triangle() {}
void operator()( HDS& hds) {
string filename;
cin >> filename;
ifstream file;
file.open(&filename[0]);
string title;
file >> title;
if (title != "OFF")
{
cout << "Wrong format!" << endl;
return;
}
int nV, nF, nE;
file >> nV >> nF >> nE;
// Postcondition: `hds' is a valid polyhedral surface.
CGAL::Polyhedron_incremental_builder_3<HDS> B( hds, true);
B.begin_surface( nV, nF);
typedef typename HDS::Vertex Vertex;
typedef typename Vertex::Point Point;
for (int idx = 0; idx < nV; idx ++)
{
double x, y, z;
file >> x >> y >> z;
B.add_vertex( Point( x, y, z));
}
for (int fidx = 0; fidx < nF; fidx ++)
{
int nP;
file >> nP;
B.begin_facet();
for (int i = 0; i < nP; i ++)
{
int idx;
file >> idx;
B.add_vertex_to_facet(idx);
}
B.end_facet();
}
B.end_surface();
file.close();
}
};
void LoadOFF(Polyhedron &P)
{
Build_triangle<HalfedgeDS> triangle;
P.delegate( triangle);
}
void k_ring(Polyhedron &P, Vertex_handle v, size_t k, vector<Vertex_handle> &neigh_vtx)
{
neigh_vtx.clear();
neigh_vtx.push_back(v);
int idx_lv = 0; // pointing the neighboring vertices on current level
int idx_lv_end;
for (size_t lv = 0; lv < k; lv++)
{
idx_lv_end = neigh_vtx.size();
for ( ;idx_lv < idx_lv_end; idx_lv++ )
{
Vertex_handle vh = neigh_vtx[idx_lv];
HV_circulator wc = vh->vertex_begin(), done(wc);
do {
Vertex_handle wh = wc->opposite()->vertex();
vector<Vertex_handle> ::iterator result = find(neigh_vtx.begin(), neigh_vtx.end(), wh);
if (result == neigh_vtx.end())
{
neigh_vtx.push_back(wh);
}
++wc;
}while(wc != done);
}
}
}
int main() {
Polyhedron P;
string filename;
cin >> filename;
ifstream file;
file.open(&filename[0]);
file >> P;
cout << P.size_of_vertices() << " vertices; " << P.size_of_facets() << "facets" << endl;
vector<Vertex_handle> neigh_vtx;
cout << "Determine level of k-ring: ";
size_t k;
cin >> k;
cout << "Determine vertex index: ";
k_ring(P, P.vertices_begin(), k, neigh_vtx);
cout << endl << neigh_vtx.size() << " neighboring vertices:" << endl;
/*for (int i = 0; i < neigh_vtx.size(); i++)
{
cout << neigh_vtx[i] << endl;
}*/
return 0;
}

View File

@ -0,0 +1,71 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Polyhedron_incremental_builder_3.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <iostream>
#include <string>
#include <map>
#include <list>
#include <fstream>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef CGAL::Polyhedron_3<Kernel> Polyhedron;
typedef Polyhedron::Vertex_const_handle Vertex_handle;
typedef Polyhedron::Halfedge_around_vertex_const_circulator HV_circulator;
void load_OFF(Polyhedron &P)
{
}
void extract_k_ring(const Polyhedron &P, Vertex_handle v, int k)
{
// The map stores the distance of the vertex,
// and serves at the same time to find out if we visited the vertex already
std::map<Vertex_handle, int> dist;
// The queue stores the vertices in increasing distance
std::list<Vertex_handle> queue;
dist[v] = 0;
queue.push_back(v);
while(! queue.empty()){
v = queue.front();
int d = dist[v];
// When we encounter the first vertex at distance k
// we can be sure that the points in queue are exactly those at distance k
if(d == k){
std::cerr << queue.size() << " vertices at distance " << k << std::endl;
break;
}
queue.pop_front();
HV_circulator wc = v->vertex_begin(), done(wc);
do {
Vertex_handle wh = wc->opposite()->vertex();
if(dist.find(wh) == dist.end()){
dist[wh] = d+1;
queue.push_back(wh);
}
++wc;
}while(wc != done);
}
}
int main() {
Polyhedron P;
std::cin >> P;
std:: cout << P.size_of_vertices() << " vertices; " << P.size_of_facets() << "facets" << std::endl;
\
int k=3;
extract_k_ring(P, P.vertices_begin(), k);
return 0;
}

View File

@ -0,0 +1,91 @@
#include <CGAL/Cartesian.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/Polyhedron_items_with_id_3.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
#include <CGAL/boost/graph/properties_Polyhedron_3.h>
#include <iostream>
#include <list>
#include <fstream>
typedef CGAL::Cartesian<double> Kernel;
//typedef Kernel::Point_3 Point;
typedef CGAL::Polyhedron_3<Kernel,CGAL::Polyhedron_items_with_id_3> Polyhedron;
typedef boost::graph_traits<Polyhedron>::vertex_descriptor vertex_descriptor;
typedef boost::graph_traits<Polyhedron>::vertex_iterator vertex_iterator;
typedef boost::graph_traits<Polyhedron>::edge_descriptor edge_descriptor;
typedef boost::graph_traits<Polyhedron>::out_edge_iterator out_edge_iterator;
using namespace std;
void k_ring(Polyhedron &P, vertex_descriptor v, size_t k, vector<vertex_descriptor> &neigh_vtx)
{
neigh_vtx.clear();
neigh_vtx.push_back(v);
int idx_lv = 0; // pointing the neighboring vertices on current level
int idx_lv_end;
for (size_t lv = 0; lv < k; lv++)
{
idx_lv_end = neigh_vtx.size();
for ( ;idx_lv < idx_lv_end; idx_lv++ )
{
vertex_descriptor vd = neigh_vtx[idx_lv];
out_edge_iterator e, e_end;
for (boost::tie(e,e_end) = boost::out_edges(vd, P); e != e_end; e++)
{
vertex_descriptor vt = boost::target(*e, P);
vector<vertex_descriptor> ::iterator result = find(neigh_vtx.begin(), neigh_vtx.end(), vt);
if (result == neigh_vtx.end())
{
neigh_vtx.push_back(vt);
}
}
}
}
}
int main() {
/////////// input OFF file /////////////////////////
Polyhedron P;
string filename;
cout << "Input filename: ";
cin >> filename;
ifstream file;
file.open(&filename[0]);
file >> P;
cout << P.size_of_vertices() << " vertices; " << P.size_of_facets() << "facets" << endl;
////////// extract k-ring vertices ////////////////////////
vector<vertex_descriptor> neigh_vtx;
cout << "Determine level of k-ring: ";
size_t k;
cin >> k;
//cout << "Determine vertex index: ";
vertex_iterator vb, ve;
boost::tie(vb,ve) = boost::vertices(P);
k_ring(P, *vb, k, neigh_vtx);
///////// output indices of neighboting vertices ///////////////////////
int index = 0;
// boost::tie assigns the first and second element of the std::pair
// returned by boost::vertices to the variables vb and ve
for(boost::tie(vb,ve)=boost::vertices(P); vb!=ve; ++vb ){
vertex_descriptor vd = *vb;
vd->id() = index++;
}
cout << endl << neigh_vtx.size() << " neighboring vertices:" << endl;
for (int i = 0; i < neigh_vtx.size(); i++)
{
cout << neigh_vtx[i]->id() << endl;
}
return 0;
}

View File

@ -0,0 +1,874 @@
// Copyright (c) 2011 GeometryFactory
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org); you may redistribute it under
// the terms of the Q Public License version 1.0.
// See the file LICENSE.QPL 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) : Yin Xu, Andreas Fabri
#ifndef CGAL_DEFORM_MESH_H
#define CGAL_DEFORM_MESH_H
#include <CGAL/trace.h>
#include <CGAL/Timer.h>
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
#include <CGAL/boost/graph/properties_Polyhedron_3.h>
#include <CGAL/boost/graph/halfedge_graph_traits_Polyhedron_3.h>
#include <CGAL/FPU_extension.h>
#include <Eigen/Eigen>
#include <Eigen/SVD>
namespace CGAL {
template <class Polyhedron, class SparseLinearAlgebraTraits_d,
class VertexIndexMap, class EdgeIndexMap>
class Deform_mesh
{
// Public types
public:
// Geometric types
typedef typename Polyhedron::Traits Kernel;
typedef typename Kernel::Vector_3 Vector;
typedef typename Kernel::Point_3 Point;
// Repeat Polyhedron types
typedef typename boost::graph_traits<Polyhedron>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<Polyhedron>::vertex_iterator vertex_iterator;
typedef typename boost::graph_traits<Polyhedron>::edge_descriptor edge_descriptor;
typedef typename boost::graph_traits<Polyhedron>::edge_iterator edge_iterator;
typedef typename boost::graph_traits<Polyhedron>::in_edge_iterator in_edge_iterator;
// Data members.
public:
Polyhedron& polyhedron; // source mesh, can not be modified
std::vector<vertex_descriptor> roi;
std::vector<vertex_descriptor> hdl; // user specified handles, storing the target positions
std::vector<vertex_descriptor> ros; // region of solution, including roi and hard constraints outside roi
VertexIndexMap vertex_index_map; // storing indices of all vertices
EdgeIndexMap edge_index_map; // storing indices of all edges
std::vector<std::size_t> ros_id; // index of ros vertices
std::vector<std::size_t> is_roi; // flag indicating vertex inside roi or not
std::vector<std::size_t> is_hdl;
unsigned int iterations; // number of maximal iterations
double tolerance; // tolerance of convergence
std::vector<Eigen::Matrix3d> rot_mtr; // rotation matrices of ros vertices
std::vector<double> edge_weight; // weight of edges
SparseLinearAlgebraTraits_d m_solver; // linear sparse solver
std::vector<Point> solution; // storing position of all vertices during iterations
std::vector<Point> original;
// Public methods
public:
// The constructor gets the polyhedron that we will model
Deform_mesh(Polyhedron& P, const VertexIndexMap& vertex_index_map_, const EdgeIndexMap& edge_index_map_)
:polyhedron(P), vertex_index_map(vertex_index_map_), edge_index_map(edge_index_map_)
{
// initialize index maps
vertex_iterator vb, ve;
int idx = 0;
for(boost::tie(vb,ve) = boost::vertices(polyhedron); vb != ve; ++vb )
{
put(vertex_index_map, *vb, idx++);
}
edge_iterator eb, ee;
idx = 0;
for(boost::tie(eb,ee) = boost::edges(polyhedron); eb != ee; ++eb )
{
boost::put(edge_index_map, *eb, idx++);
}
// initialize solution
for(boost::tie(vb,ve) = boost::vertices(polyhedron); vb != ve; ++vb )
{
solution.push_back( (*vb)->point() );
original.push_back( (*vb)->point() );
}
// initialize flag vectors of roi, handle, ros
ros_id.resize(boost::num_vertices(polyhedron), 0);
is_roi.resize(boost::num_vertices(polyhedron), 0);
is_hdl.resize(boost::num_vertices(polyhedron), 0);
// AF: What is a good number of iterations
// YX: I will add another new threshold according to energy value.
iterations = 5;
tolerance = 1e-4;
}
void clear_roi()
{
roi.clear();
is_roi.clear();
is_roi.resize( boost::num_vertices(polyhedron), 0 );
}
void insert_roi(vertex_descriptor vd)
{
std::size_t idx = get(vertex_index_map, vd);
if (!is_roi[idx])
{
roi.push_back(vd);
is_roi[idx] = 1;
}
}
// Re-assign handles from begin to end
void assign_handles(vertex_iterator begin, vertex_iterator end)
{
hdl.clear();
hdl.insert(hdl.end(), begin, end);
is_hdl.clear();
is_hdl.resize( boost::num_vertices(polyhedron), 0 ); // mark all the vertices as handle or not
for (int i = 0; i < hdl.size(); i++)
{
is_hdl[ get(vertex_index_map, hdl[i]) ] = 1;
}
}
void clear_handles()
{
hdl.clear();
is_hdl.clear();
is_hdl.resize( boost::num_vertices(polyhedron), 0 );
}
void insert_handle(vertex_descriptor vd)
{
std::size_t idx = get(vertex_index_map, vd);
if (!is_hdl[idx])
{
hdl.push_back(vd);
is_hdl[idx] = 1;
}
}
// compute cotangent weights of all edges
void compute_edge_weight()
{
// refer the information that whether the weight of an edge has already computed
std::vector<int> edge_weight_computed(boost::num_edges(polyhedron));
edge_weight.clear();
edge_weight.resize( boost::num_edges(polyhedron), 0 );
edge_iterator eb, ee;
for(boost::tie(eb,ee) = boost::edges(polyhedron); eb != ee; ++eb )
{
std::size_t e_idx = boost::get(edge_index_map, *eb);
if ( !edge_weight_computed[e_idx] )
{
double weight = cot_weight(*eb);
// replace cotangent weight by mean-value coordinate
if ( weight < 0 )
{
weight = mean_value(*eb);
edge_weight[e_idx] = weight;
edge_weight_computed[e_idx] = 1;
// assign the weights to opposite edges
edge_descriptor e_oppo = CGAL::opposite_edge(*eb, polyhedron);
std::size_t e_oppo_idx = boost::get(edge_index_map, e_oppo);
edge_weight[e_oppo_idx] = mean_value(e_oppo);
edge_weight_computed[e_oppo_idx] = 1;
}
else
{
edge_weight[e_idx] = weight;
edge_weight_computed[e_idx] = 1;
// assign the weights to opposite edges
edge_descriptor e_oppo = CGAL::opposite_edge(*eb, polyhedron);
std::size_t e_oppo_idx = boost::get(edge_index_map, e_oppo);
edge_weight[e_oppo_idx] = weight;
edge_weight_computed[e_oppo_idx] = 1;
}
}
}
}
// find region of solution, including roi and hard constraints, which is the 1-ring vertices out roi
void region_of_solution()
{
ros.clear();
ros.insert(ros.end(),roi.begin(), roi.end());
// initialize the indices of ros vertices
ros_id.clear();
ros_id.resize(boost::num_vertices(polyhedron), -1);
std::size_t ros_idx;
for ( ros_idx = 0; ros_idx < ros.size(); ros_idx++)
{
ros_id[ get(vertex_index_map, ros[ros_idx]) ] = ros_idx;
}
for (std::size_t i = 0;i < roi.size(); i++)
{
vertex_descriptor vd = roi[i];
in_edge_iterator e, e_end;
for (boost::tie(e,e_end) = boost::in_edges(vd, polyhedron); e != e_end; e++)
{
vertex_descriptor vt = boost::source(*e, polyhedron);
std::size_t idx = get(vertex_index_map, vt);
if ( !is_roi[idx] && ros_id[idx] == -1 ) // neighboring vertices outside roi && not visited
{
ros.push_back(vt);
ros_id[idx] = ros_idx++;
}
}
}
// initialize the rotation matrices with the same size of ROS
rot_mtr.clear();
rot_mtr.resize(ros.size());
for (std::size_t i = 0; i < ros.size(); i++)
{
rot_mtr[i].setIdentity();
}
}
// Before we can model we have to do some precomputation
///
/// @commentheading Template parameters:
/// @param SparseLinearAlgebraTraits_d Definite positive sparse linear solver.
void preprocess()
{
CGAL_TRACE_STREAM << "Calls preprocess()\n";
Timer task_timer; task_timer.start();
CGAL_TRACE_STREAM << " Creates matrix...\n";
compute_edge_weight();
region_of_solution();
// Assemble linear system A*X=B
typename SparseLinearAlgebraTraits_d::Matrix A(ros.size()); // matrix is definite positive, and not necessarily symmetric
assemble_laplacian(A);
CGAL_TRACE_STREAM << " Creates " << ros.size() << "*" << ros.size() << " matrix: done (" << task_timer.time() << " s)\n";
CGAL_TRACE_STREAM << " Pre-factorizing linear system...\n";
// Pre-factorizing the linear system A*X=B
task_timer.reset();
double D;
if(!m_solver.pre_factor(A, D))
return;
CGAL_TRACE_STREAM << " Pre-factorizing linear system: done (" << task_timer.time() << " s)\n";
}
// Assemble Laplacian matrix A of linear system A*X=B
///
/// @commentheading Template parameters:
/// @param SparseLinearAlgebraTraits_d definite positive sparse linear solver.
void assemble_laplacian(typename SparseLinearAlgebraTraits_d::Matrix& A)
{
// initialize the Laplacian matrix
for (int i = 0; i < ros.size(); i++)
{
A.set_coef(i, i, 1.0, true);
}
/// assign cotangent Laplacian to ros vertices
for(std::size_t i = 0; i < ros.size(); i++)
{
vertex_descriptor vi = ros[i];
std::size_t vertex_idx_i = get(vertex_index_map, vi);
if ( is_roi[vertex_idx_i] && !is_hdl[vertex_idx_i] ) // vertices of ( roi - hdl )
{
double diagonal = 0;
in_edge_iterator e, e_end;
for (boost::tie(e,e_end) = boost::in_edges(vi, polyhedron); e != e_end; e++)
{
vertex_descriptor vj = boost::source(*e, polyhedron);
double wij = edge_weight[ boost::get(edge_index_map, *e) ]; // cotangent Laplacian weights
std::size_t ros_idx_j = ros_id[ get(vertex_index_map, vj) ];
A.set_coef(i, ros_idx_j, -wij, true); // off-diagonal coefficient
diagonal += wij;
}
// diagonal coefficient
A.set_coef(i, i, diagonal);
}
}
}
// Returns the cotangent weight of specified edge_descriptor
double cot_weight(edge_descriptor e)
{
vertex_descriptor v0 = boost::target(e, polyhedron);
vertex_descriptor v1 = boost::source(e, polyhedron);
// Only one triangle for border edges
if (boost::get(CGAL::edge_is_border, polyhedron, e) ||
boost::get(CGAL::edge_is_border, polyhedron, CGAL::opposite_edge(e, polyhedron)))
{
edge_descriptor e_cw = CGAL::next_edge_cw(e, polyhedron);
vertex_descriptor v2 = boost::source(e_cw, polyhedron);
if (boost::get(CGAL::edge_is_border, polyhedron, e_cw) ||
boost::get(CGAL::edge_is_border, polyhedron, CGAL::opposite_edge(e_cw, polyhedron)) )
{
edge_descriptor e_ccw = CGAL::next_edge_ccw(e, polyhedron);
v2 = boost::source(e_ccw, polyhedron);
}
return ( cot_value(v0, v2, v1)/2.0 );
}
else
{
edge_descriptor e_cw = CGAL::next_edge_cw(e, polyhedron);
vertex_descriptor v2 = boost::source(e_cw, polyhedron);
edge_descriptor e_ccw = CGAL::next_edge_ccw(e, polyhedron);
vertex_descriptor v3 = boost::source(e_ccw, polyhedron);
return ( cot_value(v0, v2, v1)/2.0 + cot_value(v0, v3, v1)/2.0 );
}
}
// Returns the cotangent value of angle v0_v1_v2
double cot_value(vertex_descriptor v0, vertex_descriptor v1, vertex_descriptor v2)
{
Vector vec0 = v1->point() - v2->point();
Vector vec1 = v2->point() - v0->point();
Vector vec2 = v0->point() - v1->point();
double e0_square = vec0.squared_length();
double e1_square = vec1.squared_length();
double e2_square = vec2.squared_length();
double e0 = std::sqrt(e0_square);
double e2 = std::sqrt(e2_square);
double cos_angle = ( e0_square + e2_square - e1_square ) / 2.0 / e0 / e2;
double sin_angle = std::sqrt(1-cos_angle*cos_angle);
return (cos_angle/sin_angle);
}
// Returns the tangent value of half angle v0_v1_v2/2
double half_tan_value(vertex_descriptor v0, vertex_descriptor v1, vertex_descriptor v2)
{
Vector vec0 = v1->point() - v2->point();
Vector vec1 = v2->point() - v0->point();
Vector vec2 = v0->point() - v1->point();
double e0_square = vec0.squared_length();
double e1_square = vec1.squared_length();
double e2_square = vec2.squared_length();
double e0 = std::sqrt(e0_square);
double e2 = std::sqrt(e2_square);
double cos_angle = ( e0_square + e2_square - e1_square ) / 2.0 / e0 / e2;
double angle = acos(cos_angle);
return ( tan(angle/2.0) );
}
// Returns the mean-value coordinate of specified edge_descriptor
double mean_value(edge_descriptor e)
{
vertex_descriptor v0 = boost::target(e, polyhedron);
vertex_descriptor v1 = boost::source(e, polyhedron);
Vector vec = v0->point() - v1->point();
double norm = std::sqrt( vec.squared_length() );
// Only one triangle for border edges
if (boost::get(CGAL::edge_is_border, polyhedron, e) ||
boost::get(CGAL::edge_is_border, polyhedron, CGAL::opposite_edge(e, polyhedron)))
{
edge_descriptor e_cw = CGAL::next_edge_cw(e, polyhedron);
vertex_descriptor v2 = boost::source(e_cw, polyhedron);
if (boost::get(CGAL::edge_is_border, polyhedron, e_cw) ||
boost::get(CGAL::edge_is_border, polyhedron, CGAL::opposite_edge(e_cw, polyhedron)) )
{
edge_descriptor e_ccw = CGAL::next_edge_ccw(e, polyhedron);
v2 = boost::source(e_ccw, polyhedron);
}
return ( half_tan_value(v1, v0, v2)/norm );
}
else
{
edge_descriptor e_cw = CGAL::next_edge_cw(e, polyhedron);
vertex_descriptor v2 = boost::source(e_cw, polyhedron);
edge_descriptor e_ccw = CGAL::next_edge_ccw(e, polyhedron);
vertex_descriptor v3 = boost::source(e_ccw, polyhedron);
return ( half_tan_value(v1, v0, v2)/norm + half_tan_value(v1, v0, v3)/norm );
}
}
// Set the number of iterations made in operator()
void set_iterations(unsigned int ite)
{
iterations = ite;
}
// Set the tolerance of convergence made in operator()
void set_tolerance(double tole)
{
tolerance = tole;
}
// The operator will be called in a real time loop from the GUI.
// assign translation vector to all handles
void operator()(const Vector& translation)
{
for (std::size_t idx = 0; idx < hdl.size(); idx++)
{
vertex_descriptor vd = hdl[idx];
solution[get(vertex_index_map, vd)] = original[get(vertex_index_map,vd)] + translation;
}
}
// The operator will be called in a real time loop from the GUI.
// assign translation vector to specific handle
void operator()(vertex_descriptor vd, const Vector& translation)
{
std::size_t idx = get(vertex_index_map, vd);
solution[idx] = original[idx] + translation;
}
#ifdef CGAL_DEFORM_ROTATION
template <typename Quaternion, typename Vect>
void operator()(vertex_descriptor vd, const Point& rotation_center, const Quaternion& quat, const Vect& translation)
{
std::size_t idx = get(vertex_index_map, vd);
Point p = CGAL::ORIGIN + ( original[idx] - rotation_center);
Vect v = quat * Vect(p.x(),p.y(),p.z());
p = Point(v[0], v[1], v[2]) + ( rotation_center - CGAL::ORIGIN);
p = p + Vector(translation[0],translation[1],translation[2]);
solution[idx] = p;
}
#endif // CGAL_DEFORM_ROTATION
// Local step of iterations, computing optimal rotation matrices using SVD decomposition, stable
void optimal_rotations_svd()
{
Eigen::Matrix3d u, v; // orthogonal matrices
Eigen::Vector3d w; // singular values
Eigen::Matrix3d cov; // covariance matrix
Eigen::JacobiSVD<Eigen::Matrix3d> svd; // SVD solver
Eigen::Matrix3d r;
int num_neg = 0;
// only accumulate ros vertices
for ( std::size_t i = 0; i < ros.size(); i++ )
{
vertex_descriptor vi = ros[i];
// compute covariance matrix
cov.setZero();
in_edge_iterator e, e_end;
for (boost::tie(e,e_end) = boost::in_edges(vi, polyhedron); e != e_end; e++)
{
vertex_descriptor vj = boost::source(*e, polyhedron);
Vector pij = original[get(vertex_index_map, vi)] - original[get(vertex_index_map, vj)];
Vector qij = solution[get(vertex_index_map, vi)] - solution[get(vertex_index_map, vj)];
double wij = edge_weight[boost::get(edge_index_map, *e)];
for (int j = 0; j < 3; j++)
{
for (int k = 0; k < 3; k++)
{
cov(j, k) += wij*pij[j]*qij[k];
}
}
}
// svd decomposition
svd.compute( cov, Eigen::ComputeFullU | Eigen::ComputeFullV );
u = svd.matrixU(); v = svd.matrixV();
// extract rotation matrix
r = v*u.transpose();
// checking negative determinant of r
if ( r.determinant() < 0 ) // changing the sign of column corresponding to smallest singular value
{
num_neg++;
w = svd.singularValues();
for (int j = 0; j < 3; j++)
{
int j0 = j;
int j1 = (j+1)%3;
int j2 = (j1+1)%3;
if ( w[j0] <= w[j1] && w[j0] <= w[j2] ) // smallest singular value as j0
{
u(0, j0) = - u(0, j0);
u(1, j0) = - u(1, j0);
u(2, j0) = - u(2, j0);
break;
}
}
// re-extract rotation matrix
r = v*u.transpose();
}
rot_mtr[i] = r;
}
CGAL_TRACE_STREAM << num_neg << " negative rotations\n";
}
#ifdef CGAL_DEFORM_EXPERIMENTAL // Experimental stuff, needs further testing
double norm_1(const Eigen::Matrix3d& X)
{
double sum = 0;
for ( int i = 0; i < 3; i++ )
{
for ( int j = 0; j < 3; j++ )
{
sum += abs(X(i,j));
}
}
return sum;
}
double norm_inf(const Eigen::Matrix3d& X)
{
double max_abs = abs(X(0,0));
for ( int i = 0; i < 3; i++ )
{
for ( int j = 0; j < 3; j++ )
{
double new_abs = abs(X(i,j));
if ( new_abs > max_abs )
{
max_abs = new_abs;
}
}
}
return max_abs;
}
// polar decomposition using Newton's method, with warm start, stable but slow
// not used, need to be investigated later
void polar_newton(const Eigen::Matrix3d& A, Eigen::Matrix3d &U, double tole)
{
Eigen::Matrix3d X = A;
Eigen::Matrix3d Y;
double alpha, beta, gamma;
do
{
Y = X.inverse();
alpha = sqrt( norm_1(X) * norm_inf(X) );
beta = sqrt( norm_1(Y) * norm_inf(Y) );
gamma = sqrt(beta/alpha);
X = 0.5*( gamma*X + Y.transpose()/gamma );
} while ( abs(gamma-1) > tole );
U = X;
}
// polar decomposition using Eigen, 5 times faster than SVD
template<typename Mat>
void polar_eigen(const Mat& A, Mat& R, bool& SVD)
{
typedef typename Mat::Scalar Scalar;
typedef Eigen::Matrix<typename Mat::Scalar,3,1> Vec;
const Scalar th = std::sqrt(Eigen::NumTraits<Scalar>::dummy_precision());
Eigen::SelfAdjointEigenSolver<Mat> eig;
feclearexcept(FE_UNDERFLOW);
eig.computeDirect(A.transpose()*A);
if(fetestexcept(FE_UNDERFLOW) || eig.eigenvalues()(0)/eig.eigenvalues()(2)<th)
{
// The computation of the eigenvalues might have diverged.
// Fallback to an accurate SVD based decomposiiton method.
Eigen::JacobiSVD<Mat> svd;
svd.compute(A, Eigen::ComputeFullU | Eigen::ComputeFullV );
const Mat& u = svd.matrixU(); const Mat& v = svd.matrixV();
R = u*v.transpose();
SVD = true;
return;
}
Vec S = eig.eigenvalues().cwiseSqrt();
R = A * eig.eigenvectors() * S.asDiagonal().inverse()
* eig.eigenvectors().transpose();
SVD = false;
if(std::abs(R.squaredNorm()-3.) > th)
{
// The computation of the eigenvalues might have diverged.
// Fallback to an accurate SVD based decomposiiton method.
Eigen::JacobiSVD<Mat> svd;
svd.compute(A, Eigen::ComputeFullU | Eigen::ComputeFullV );
const Mat& u = svd.matrixU(); const Mat& v = svd.matrixV();
R = u*v.transpose();
SVD = true;
return;
}
}
// Local step of iterations, computing optimal rotation matrices using Polar decomposition
void optimal_rotations_polar()
{
Eigen::Matrix3d u, v; // orthogonal matrices
Eigen::Vector3d w; // singular values
Eigen::Matrix3d cov; // covariance matrix
Eigen::Matrix3d r;
Eigen::JacobiSVD<Eigen::Matrix3d> svd; // SVD solver, for non-positive covariance matrices
int num_svd = 0;
bool SVD = false;
// only accumulate ros vertices
for ( std::size_t i = 0; i < ros.size(); i++ )
{
vertex_descriptor vi = ros[i];
// compute covariance matrix
cov.setZero();
in_edge_iterator e, e_end;
for (boost::tie(e,e_end) = boost::in_edges(vi, polyhedron); e != e_end; e++)
{
vertex_descriptor vj = boost::source(*e, polyhedron);
Vector pij = original[get(vertex_index_map, vi)] - original[get(vertex_index_map, vj)];
Vector qij = solution[get(vertex_index_map, vi)] - solution[get(vertex_index_map, vj)];
double wij = edge_weight[boost::get(edge_index_map, *e)];
for (int j = 0; j < 3; j++)
{
for (int k = 0; k < 3; k++)
{
cov(j, k) += wij*pij[j]*qij[k];
}
}
}
// svd decomposition
if (cov.determinant() > 0)
{
polar_eigen<Eigen::Matrix3d> (cov, r, SVD);
//polar_newton(cov, r, 1e-4);
if(SVD)
num_svd++;
r.transposeInPlace(); // the optimal rotation matrix should be transpose of decomposition result
}
else
{
svd.compute( cov, Eigen::ComputeFullU | Eigen::ComputeFullV );
u = svd.matrixU(); v = svd.matrixV(); w = svd.singularValues();
r = v*u.transpose();
num_svd++;
}
// checking negative determinant of covariance matrix
if ( r.determinant() < 0 ) // back to SVD method
{
if (cov.determinant() > 0)
{
svd.compute( cov, Eigen::ComputeFullU | Eigen::ComputeFullV );
u = svd.matrixU(); v = svd.matrixV(); w = svd.singularValues();
num_svd++;
}
for (int j = 0; j < 3; j++)
{
int j0 = j;
int j1 = (j+1)%3;
int j2 = (j1+1)%3;
if ( w[j0] <= w[j1] && w[j0] <= w[j2] ) // smallest singular value as j0
{
u(0, j0) = - u(0, j0);
u(1, j0) = - u(1, j0);
u(2, j0) = - u(2, j0);
break;
}
}
// re-extract rotation matrix
r = v*u.transpose();
}
rot_mtr[i] = r;
}
double svd_percent = (double)(num_svd)/ros.size();
CGAL_TRACE_STREAM << svd_percent*100 << "% percentage SVD decompositions;";
CGAL_TRACE_STREAM << num_svd << " SVD decompositions\n";
}
#endif
// Global step of iterations, updating solution
void update_solution()
{
typename SparseLinearAlgebraTraits_d::Vector X(ros.size()), Bx(ros.size());
typename SparseLinearAlgebraTraits_d::Vector Y(ros.size()), By(ros.size());
typename SparseLinearAlgebraTraits_d::Vector Z(ros.size()), Bz(ros.size());
// assemble right columns of linear system
for ( std::size_t i = 0; i < ros.size(); i++ )
{
vertex_descriptor vi = ros[i];
std::size_t vertex_idx_i = get(vertex_index_map, vi);
if ( !is_roi[vertex_idx_i] || is_hdl[vertex_idx_i] ) // hard constraints or handle vertices
{
Bx[i] = solution[vertex_idx_i].x(); By[i] = solution[vertex_idx_i].y(); Bz[i] = solution[vertex_idx_i].z();
}
else // ( roi - handle ) vertices
{
Bx[i] = 0; By[i] = 0; Bz[i] = 0;
in_edge_iterator e, e_end;
Point& pi = original[get(vertex_index_map, vi)];
for (boost::tie(e,e_end) = boost::in_edges(vi, polyhedron); e != e_end; e++)
{
vertex_descriptor vj = boost::source(*e, polyhedron);
std::size_t ros_idx_j = ros_id[ get(vertex_index_map, vj) ];
Vector pij = pi - original[get(vertex_index_map, vj)];
double wij = edge_weight[boost::get(edge_index_map, *e)];
Vector rot_p(0, 0, 0); // vector ( r_i + r_j )*p_ij
for (int j = 0; j < 3; j++)
{
double x = ( rot_mtr[i](0, j) + rot_mtr[ros_idx_j](0, j) ) * pij[j];
double y = ( rot_mtr[i](1, j) + rot_mtr[ros_idx_j](1, j) ) * pij[j];
double z = ( rot_mtr[i](2, j) + rot_mtr[ros_idx_j](2, j) ) * pij[j];
rot_p = rot_p + Vector(x, y, z);
}
Vector vec = wij*rot_p/2.0;
Bx[i] += vec.x(); By[i] += vec.y(); Bz[i] += vec.z();
}
}
}
// solve "A*X = B".
m_solver.linear_solver(Bx, X); m_solver.linear_solver(By, Y); m_solver.linear_solver(Bz, Z);
// copy to solution
for (std::size_t i = 0; i < ros.size(); i++)
{
Point p(X[i], Y[i], Z[i]);
solution[get(vertex_index_map, ros[i])] = p;
}
}
// Compute modeling energy
double energy()
{
double sum_of_energy = 0;
// only accumulate ros vertices
for( std::size_t i = 0; i < ros.size(); i++ )
{
vertex_descriptor vi = ros[i];
in_edge_iterator e, e_end;
for (boost::tie(e,e_end) = boost::in_edges(vi, polyhedron); e != e_end; e++)
{
vertex_descriptor vj = boost::source(*e, polyhedron);
Vector pij = original[get(vertex_index_map, vi)] - original[get(vertex_index_map, vj)];
double wij = edge_weight[boost::get(edge_index_map, *e)];
Vector rot_p(0, 0, 0); // vector rot_i*p_ij
for (int j = 0; j < 3; j++)
{
double x = rot_mtr[i](0, j) * pij[j];
double y = rot_mtr[i](1, j) * pij[j];
double z = rot_mtr[i](2, j) * pij[j];
Vector v(x, y, z);
rot_p = rot_p + v;
}
Vector qij = solution[get(vertex_index_map, vi)] - solution[get(vertex_index_map, vj)];
sum_of_energy += wij*(qij - rot_p).squared_length();
}
}
return sum_of_energy;
}
// Deformation on roi vertices
void deform()
{
double energy_this = 0;
double energy_last;
// iterations
CGAL_TRACE_STREAM << "iteration started...\n";
for ( unsigned int ite = 0; ite < iterations; ite ++)
{
update_solution();
#ifdef CGAL_DEFORM_EXPERIMENTAL
optimal_rotations_polar(); // polar decomposition for optimal rotations, faster than SVD but unstable
#else
optimal_rotations_svd();
#endif
energy_last = energy_this;
energy_this = energy();
CGAL_TRACE_STREAM << ite << " iterations: energy = " << energy_this << "\n";
if ( abs((energy_last-energy_this)/energy_this) < tolerance )
{
break;
}
}
CGAL_TRACE_STREAM << "iteration end!\n";
// copy solution to target mesh
assign_solution();
}
// Assign solution to target mesh
void assign_solution()
{
for(std::size_t i = 0; i < roi.size(); ++i){
roi[i]->point() = solution[get(vertex_index_map, roi[i])];
}
}
// Undo: reset P to be the copied polyhedron
void undo()
{
std::size_t i = 0;
vertex_iterator vb, ve;
for(boost::tie(vb,ve) = boost::vertices(polyhedron); vb != ve; ++vb )
{
(*vb)->point() = original[i++];
}
}
};
} //namespace CGAL
#endif // CGAL_DEFORM_MESH_H

View File

@ -0,0 +1 @@
GeometryFactory (France)

View File

@ -0,0 +1 @@
GPL (v3 or later)

View File

@ -0,0 +1 @@
Andreas Fabri <Andreas.Fabri@geometryfactory.com>