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()
|
||||
|
||||
|
|
@ -92,6 +92,15 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND)
|
|||
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)
|
||||
|
||||
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
|
||||
if(NOT EIGEN3_FOUND AND NOT LAPACK_FOUND)
|
||||
message(STATUS "NOTICE: Eigen 3.1 (or greater) and LAPACK is not found. curvatures estimation will not be available.")
|
||||
|
|
@ -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( cameraUI_FILES Camera_positions_list.ui )
|
||||
qt4_wrap_ui( PreferencesUI_FILES Preferences.ui )
|
||||
qt4_wrap_ui( editionUI_FILES Deform_mesh.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(edit_polyhedron_plugin Polyhedron_demo_edit_polyhedron_plugin)
|
||||
if(TAUCS_FOUND OR ( EIGEN3_FOUND AND SUPERLU_FOUND ) )
|
||||
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)
|
||||
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_edit_polyhedron_item.h"
|
||||
#include <QAction>
|
||||
#include <QKeySequence>
|
||||
#include <QMainWindow>
|
||||
#include <QMessageBox>
|
||||
#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 :
|
||||
public QObject,
|
||||
|
|
@ -16,10 +63,13 @@ class Polyhedron_demo_edit_polyhedron_plugin :
|
|||
|
||||
public:
|
||||
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);
|
||||
|
||||
QList<QAction*> actions() const {
|
||||
return QList<QAction*>() << actionToggleEdit;
|
||||
}
|
||||
|
|
@ -35,69 +85,442 @@ public:
|
|||
return false;
|
||||
}
|
||||
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 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:
|
||||
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;
|
||||
int size;
|
||||
bool edit_mode;
|
||||
}; // 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,
|
||||
Scene_interface* scene_interface)
|
||||
{
|
||||
actionToggleEdit = new QAction(tr("Toggle &edition of item(s)"), mainWindow);
|
||||
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);
|
||||
}
|
||||
|
||||
void Polyhedron_demo_edit_polyhedron_plugin::on_actionToggleEdit_triggered() {
|
||||
bool found_polyhedron = false;
|
||||
bool edit_needed = false;
|
||||
QList<Scene_item*> changed_items;
|
||||
Q_FOREACH(Scene_interface::Item_id i, scene->selectionIndices())
|
||||
void
|
||||
Polyhedron_demo_edit_polyhedron_plugin::new_item_created(int item_id)
|
||||
{
|
||||
if(Scene_polyhedron_item* poly_item =
|
||||
qobject_cast<Scene_polyhedron_item*>(scene->item(i)))
|
||||
if(edit_mode) {
|
||||
Scene_polyhedron_item* poly_item =
|
||||
qobject_cast<Scene_polyhedron_item*>(scene->item(item_id));
|
||||
if(poly_item) {
|
||||
convert_to_edit_polyhedron(item_id, poly_item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Scene_edit_polyhedron_item*
|
||||
Polyhedron_demo_edit_polyhedron_plugin::
|
||||
convert_to_edit_polyhedron(Item_id i,
|
||||
Scene_polyhedron_item* poly_item)
|
||||
{
|
||||
found_polyhedron = true;
|
||||
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()));
|
||||
scene->replaceItem(i, edit_poly);
|
||||
changed_items.push_back(scene->item(i));
|
||||
edit_needed = true;
|
||||
|
||||
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()));
|
||||
} else if(Scene_edit_polyhedron_item* poly_item =
|
||||
qobject_cast<Scene_edit_polyhedron_item*>(scene->item(i)))
|
||||
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)
|
||||
{
|
||||
found_polyhedron = true;
|
||||
scene->replaceItem(i, poly_item->to_polyhedron_item());
|
||||
delete poly_item;
|
||||
Scene_polyhedron_item* poly_item = edit_item->to_polyhedron_item();
|
||||
scene->replaceItem(i, poly_item);
|
||||
delete edit_item;
|
||||
return 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)
|
||||
|
||||
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_edit_polyhedron_item* poly_edit_item =
|
||||
qobject_cast<Scene_edit_polyhedron_item*>(item);
|
||||
if(poly_edit_item) poly_edit_item->setZoneSize(size);
|
||||
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() {
|
||||
QObject* obj = sender();
|
||||
Scene_edit_polyhedron_item* edit_item =
|
||||
|
|
@ -108,18 +531,43 @@ void Polyhedron_demo_edit_polyhedron_plugin::edition() {
|
|||
return;
|
||||
}
|
||||
|
||||
typedef Kernel::Point_3 Point;
|
||||
typedef Kernel::Vector_3 Vector;
|
||||
typedef Polyhedron::Vertex_handle Vertex_handle;
|
||||
// do deformation only when handles are selected
|
||||
if (edit_item->selected_vertices().isEmpty()) return;
|
||||
|
||||
const Point& orig = edit_item->original_position();
|
||||
const Vector move_vector = edit_item->current_position() - orig;
|
||||
|
||||
Q_FOREACH(Vertex_handle vh, edit_item->selected_vertices())
|
||||
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.
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <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 <set>
|
||||
|
|
@ -14,35 +19,86 @@
|
|||
|
||||
#include <QGLViewer/manipulatedFrame.h>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef Polyhedron::Vertex_handle Vertex_handle;
|
||||
typedef Polyhedron::Halfedge_handle Halfedge_handle;
|
||||
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 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 {
|
||||
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;
|
||||
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;
|
||||
Transform_vectors selected_vectors;
|
||||
Transform_vectors non_selected_vectors;
|
||||
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
|
||||
|
||||
Scene_edit_polyhedron_item::Scene_edit_polyhedron_item(Scene_polyhedron_item* poly_item)
|
||||
: d(new Scene_edit_polyhedron_item_priv)
|
||||
{
|
||||
d->poly_item = poly_item;
|
||||
d->zone_size = 0;
|
||||
d->handlesRegionSize = 0;
|
||||
d->frame = new ManipulatedFrame();
|
||||
d->frame->setProperty("item", QVariant::fromValue<QObject*>(this));
|
||||
if(!connect(poly_item, SIGNAL(selected_vertex(void*)),
|
||||
this, SLOT(vertex_has_been_selected(void*))))
|
||||
std::cerr << __FILE__ << ": connection failed!\n";
|
||||
poly_item->enable_facets_picking(true);
|
||||
|
||||
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()
|
||||
{
|
||||
delete d->frame;
|
||||
delete d->vertex_index_map;
|
||||
delete d->dist_pmap;
|
||||
delete d;
|
||||
}
|
||||
|
||||
|
|
@ -73,19 +129,78 @@ Scene_edit_polyhedron_item::toolTip() const
|
|||
|
||||
void Scene_edit_polyhedron_item::draw() const {
|
||||
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::Color color; color.set_rgb_color(0, 0, 0);
|
||||
CGAL::GL::Color color;
|
||||
color.set_rgb_color(1.f, 0, 0);
|
||||
::glBegin(GL_POINTS);
|
||||
for(Selected_vertices_it
|
||||
it = d->selected_vertices.begin(),
|
||||
end = d->selected_vertices.end();
|
||||
it = d->selected_handles.begin(),
|
||||
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)
|
||||
{
|
||||
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->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();
|
||||
Scene_item::changed();
|
||||
d->orig_pos = current_position();
|
||||
d->last_pos = current_position();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -141,19 +256,72 @@ Scene_polyhedron_item* Scene_edit_polyhedron_item::to_polyhedron_item() const {
|
|||
}
|
||||
|
||||
void
|
||||
Scene_edit_polyhedron_item::setZoneSize(int i) {
|
||||
Scene_edit_polyhedron_item::setHandlesRegionSize(int i) {
|
||||
if(i >= 0) {
|
||||
std::cerr << "item \"" << qPrintable(name())
|
||||
<< "\".setZoneSize(" << i << ")\n";
|
||||
d->zone_size = i;
|
||||
d->handlesRegionSize = i;
|
||||
if(d->selected_vertex != Vertex_handle()) {
|
||||
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*
|
||||
Scene_edit_polyhedron_item::manipulatedFrame() {
|
||||
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>
|
||||
{
|
||||
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) {
|
||||
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);
|
||||
Vertex_handle vh = get_vertex_handle.vh;
|
||||
|
||||
std::cerr << "Selected vertex: " << void_ptr << " = " << vh->point()
|
||||
<< std::endl;
|
||||
d->selected_vertices.clear();
|
||||
|
||||
d->selected_vertices.insert(vh);
|
||||
|
||||
std::cerr << "d->zone_size = " << d->zone_size << std::endl;
|
||||
// Naive way to compute the k-neighborhood of vh, with k==d->zone_size.
|
||||
for(int i = 0; i < d->zone_size; ++i) {
|
||||
std::set<Vertex_handle> selected_vertices;
|
||||
for(Selected_vertices_it
|
||||
it = d->selected_vertices.begin(),
|
||||
end = d->selected_vertices.end();
|
||||
it != end; ++it) {
|
||||
selected_vertices.insert(*it);
|
||||
}
|
||||
BOOST_FOREACH(Vertex_handle v, selected_vertices) {
|
||||
Polyhedron::Halfedge_around_vertex_circulator
|
||||
he_it = v->vertex_begin(), he_it_end(he_it);
|
||||
if(he_it != 0) {
|
||||
do {
|
||||
const Vertex_handle other_v = he_it->opposite()->vertex();
|
||||
if( d->selected_vertices.find(other_v) == d->selected_vertices.end() )
|
||||
if (d->selected_vertex != vh)
|
||||
{
|
||||
d->selected_vertices.insert(other_v);
|
||||
// re-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);
|
||||
}
|
||||
} while(++he_it != he_it_end);
|
||||
boost::dijkstra_shortest_paths( *poly, vh,
|
||||
boost::vertex_index_map (*d->vertex_index_map).
|
||||
weight_map (edge_length_map).
|
||||
distance_map (*d->dist_pmap));
|
||||
}
|
||||
|
||||
// set new handles and ROI regions
|
||||
Selected_vertices new_handles;
|
||||
new_handles.insert(vh);
|
||||
new_handles = extend_k_ring(new_handles, d->handlesRegionSize);
|
||||
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();
|
||||
d->orig_pos = p;
|
||||
d->last_pos = p;
|
||||
d->frame->setPosition(qglviewer::Vec(p.x(), p.y(), p.z()));
|
||||
connect(d->frame, SIGNAL(modified()),
|
||||
this, SIGNAL(modified()));
|
||||
|
||||
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
|
||||
Scene_edit_polyhedron_item::selected_vertex() const {
|
||||
return d->selected_vertex;
|
||||
}
|
||||
|
||||
QList<Vertex_handle>
|
||||
Scene_edit_polyhedron_item::selected_vertices() const {
|
||||
Scene_edit_polyhedron_item::selected_handles() const {
|
||||
QList<Vertex_handle> result;
|
||||
BOOST_FOREACH(Vertex_handle vh, d->selected_vertices) {
|
||||
BOOST_FOREACH(Vertex_handle vh, d->selected_handles) {
|
||||
result << vh;
|
||||
}
|
||||
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 {
|
||||
const qglviewer::Vec vec = d->frame->position();
|
||||
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 {
|
||||
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"
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
#include "Scene_edit_polyhedron_item_config.h"
|
||||
#include "Scene_polyhedron_item.h"
|
||||
#include "Polyhedron_type.h"
|
||||
#include <CGAL/boost/graph/halfedge_graph_traits_Polyhedron_3.h>
|
||||
#include <CGAL/boost/graph/properties.h>
|
||||
#include <iostream>
|
||||
|
||||
#include <vector>
|
||||
|
|
@ -14,6 +16,12 @@
|
|||
class QMenu;
|
||||
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
|
||||
class SCENE_EDIT_POLYHEDRON_ITEM_EXPORT Scene_edit_polyhedron_item
|
||||
: public Scene_item {
|
||||
|
|
@ -35,6 +43,11 @@ public:
|
|||
// Function for displaying meta-data of the item
|
||||
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
|
||||
// QMenu* contextMenu();
|
||||
|
||||
|
|
@ -53,8 +66,31 @@ public:
|
|||
// Functions related to the edition
|
||||
Kernel::Point_3 original_position() const;
|
||||
Kernel::Point_3 current_position() const;
|
||||
Kernel::Point_3 last_position() 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
|
||||
/// transfer the ownership of the polyhedron to it.
|
||||
|
|
@ -74,8 +110,14 @@ public slots:
|
|||
double dir_x,
|
||||
double dir_y,
|
||||
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_2(void* vertex_handle);
|
||||
|
||||
signals:
|
||||
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:
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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:
|
||||
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
|
||||
class Taucs_symmetric_solver_traits
|
||||
{
|
||||
|
||||
private:
|
||||
boost::shared_ptr<taucs_io_handle> mtr;
|
||||
|
||||
// Public types
|
||||
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:
|
||||
|
||||
// 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
|
||||
{
|
||||
// Public types
|
||||
|
||||
private:
|
||||
|
||||
boost::shared_ptr<taucs_io_handle> mtr;
|
||||
|
||||
public:
|
||||
|
||||
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:
|
||||
|
||||
// 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