mirror of https://github.com/CGAL/cgal
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:
commit
c8fb9844aa
|
|
@ -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)
|
||||||
|
|
@ -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()
|
||||||
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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 &deformation</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="dockWidgetContents">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="editModeCb">
|
||||||
|
<property name="text">
|
||||||
|
<string>&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>&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>&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>
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
@ -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 */
|
||||||
|
|
@ -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_ */
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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)));
|
||||||
|
}
|
||||||
|
|
@ -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()
|
||||||
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
GeometryFactory (France)
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
GPL (v3 or later)
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Andreas Fabri <Andreas.Fabri@geometryfactory.com>
|
||||||
Loading…
Reference in New Issue