Commit e81384ea authored by Henrik Zimmer's avatar Henrik Zimmer

added the harmonic openflipper example to the repository

git-svn-id: http://www.openflipper.org/svnrepo/CoMISo/trunk@7 1355f012-dd97-4b2f-ae87-10fa9f823a57
parent c1ec7d50
include (plugin)
openflipper_plugin (DIRS DEPS CoMISo GMM Boost SUITESPARSE INCDIRS "${CMAKE_BINARY_DIR}/CoMISo" )
//=============================================================================
//
// CLASS HarmonicExamplePerObjectData
//
//=============================================================================
#ifndef HARMONICEXAMPLEPEROBJECTDATA_HH
#define HARMONICEXAMPLEPEROBJECTDATA_HH
//== INCLUDES =================================================================
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include <OpenFlipper/common/perObjectData.hh>
#include "HarmonicExampleT.hh"
//== CLASS DEFINITION =========================================================
template <class MeshT>
class HarmonicExamplePerObjectDataT : public PerObjectData
{
public:
HarmonicExamplePerObjectDataT( MeshT& _mesh) : harmonicexample_(_mesh)
{}
virtual
~HarmonicExamplePerObjectDataT()
{}
ACG::HarmonicExampleT<MeshT>& harmonicexample() { return harmonicexample_;}
private:
// create an FeatureLine
ACG::HarmonicExampleT<MeshT> harmonicexample_;
};
//=============================================================================
#endif // HARMONICEXAMPLEPEROBJECTDATA_HH defined
//=============================================================================
//=============================================================================
//
// CLASS HarmonicExamplePlugin - IMPLEMENTATION
//
//=============================================================================
//== INCLUDES =================================================================
#include <Qt>
#include <QtGui>
#include <QSpacerItem>
#include "HarmonicExamplePlugin.hh"
#include <iostream>
#include <ACG/Utils/StopWatch.hh>
#include <OpenFlipper/BasePlugin/PluginFunctions.hh>
// #include <PhySim/QtWidgets/QwtFunctionPlot.hh>
// #include <PhySim/Meshes/PrincipalCurvatureT.hh>
// #include <PhySim/Meshes/PrincipalCurvatureJetT.hh>
// #include <PhySim/Math/Algorithms.hh>
#undef min
#undef max
//== IMPLEMENTATION ==========================================================
void HarmonicExamplePlugin::initializePlugin()
{
}
//-----------------------------------------------------------------------------
bool HarmonicExamplePlugin::initializeToolbox(QWidget*& _widget)
{
tool_ = new HarmonicExampleToolbar();
_widget = tool_;
QSize size(300,300);
tool_->resize(size);
// connect button press event to function slotCompute()
connect(tool_->compute_pb, SIGNAL( clicked() ), this, SLOT( slotCompute() ) );
return true;
}
//-----------------------------------------------------------------------------
void HarmonicExamplePlugin::pluginsInitialized()
{
// emit addPickMode("Separator");
}
//-----------------------------------------------------------------------------
HarmonicExamplePlugin::HarmonicExample*
HarmonicExamplePlugin::
get_harmonicexample_object( BaseObjectData* _object )
{
// initialize PerObjectData if not done yet
if (!_object->hasObjectData(pod_name()))
{
// get mesh object
TriMesh* mesh = dynamic_cast< TriMeshObject* >( _object )->mesh();
// initialize per object data
_object->setObjectData(pod_name(), new POD(*mesh));
}
// get feature lines object
HarmonicExample* harmonicexample = dynamic_cast<HarmonicExample*>(& (dynamic_cast< POD* >(_object->objectData(pod_name() )))->harmonicexample());
return harmonicexample;
}
//-----------------------------------------------------------------------------
void HarmonicExamplePlugin::slotCompute()
{
// iterate over all target triangle meshes
for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS,DATA_TRIANGLE_MESH) ; o_it != PluginFunctions::objectsEnd(); ++o_it)
{
// get pointer to mesh
TriMesh* mesh = dynamic_cast< TriMeshObject* >( *o_it )->mesh();
if ( mesh )
{
// get feature line object and call compute function
get_harmonicexample_object( *o_it )->compute();
// set correct draw mode
TriMeshObject *mesh_obj;
mesh_obj = PluginFunctions::triMeshObject((*o_it));
mesh_obj->meshNode()->drawMode(ACG::SceneGraph::DrawModes::SOLID_POINTS_COLORED);
mesh_obj->materialNode()->disable_color_material();
}
}
}
//-----------------------------------------------------------------------------
Q_EXPORT_PLUGIN2( harmonicexampleplugin , HarmonicExamplePlugin );
//=============================================================================
//
// CLASS HarmonicExamplePlugin
//
//=============================================================================
#ifndef HARMONICEXAMPLEPLUGIN_HH
#define HARMONICEXAMPLEPLUGIN_HH
//== INCLUDES =================================================================
#include <QObject>
#include <QMenuBar>
#include <QSpinBox>
#include <OpenFlipper/common/Types.hh>
#include <OpenFlipper/BasePlugin/BaseInterface.hh>
#include <OpenFlipper/BasePlugin/ToolboxInterface.hh>
#include <OpenFlipper/BasePlugin/KeyInterface.hh>
#include <OpenFlipper/BasePlugin/MouseInterface.hh>
#include <OpenFlipper/BasePlugin/PickingInterface.hh>
#include <OpenFlipper/BasePlugin/ScriptInterface.hh>
#include <ACG/QtWidgets/QtExaminerViewer.hh>
#include <ObjectTypes/TriangleMesh/TriangleMesh.hh>
#include "HarmonicExampleToolbar.hh"
#include "HarmonicExamplePerObjectDataT.hh"
#include "HarmonicExampleT.hh"
//== CLASS DEFINITION =========================================================
class HarmonicExamplePlugin : public QObject, BaseInterface, ToolboxInterface, KeyInterface, ScriptInterface, MouseInterface, PickingInterface
{
Q_OBJECT
Q_INTERFACES(BaseInterface)
Q_INTERFACES(ToolboxInterface)
Q_INTERFACES(KeyInterface)
Q_INTERFACES(ScriptInterface)
Q_INTERFACES(MouseInterface)
Q_INTERFACES(PickingInterface)
// typedef for easy access
typedef ACG::HarmonicExampleT<TriMesh> HarmonicExample;
typedef HarmonicExamplePerObjectDataT<TriMesh> POD;
signals:
void updateView();
void updatedObject(int);
private slots:
// initialization functions
void initializePlugin();
void pluginsInitialized();
// compute
void slotCompute();
public :
~HarmonicExamplePlugin() {};
bool initializeToolbox(QWidget*& _widget);
QString name() { return (QString("HarmonicExample")); };
QString description( ) { return (QString("Computes the HarmonicExample of the the active Mesh")); };
private :
// return name of per object data
const char * pod_name() { return "HARMONICEXAMPLE_PER_OBJECT_DATA";}
// get HarmonicExample object for a given object
HarmonicExample* get_harmonicexample_object( BaseObjectData* _object );
private :
/// Widget for Toolbox
HarmonicExampleToolbar* tool_;
};
//=============================================================================
#endif // HARMONICEXAMPLEPLUGIN_HH defined
//=============================================================================
//=============================================================================
//
// CLASS HarmonicExampleT - IMPLEMENTATION
//
//=============================================================================
#define ACG_HARMONICEXAMPLET_C
//== INCLUDES =================================================================
#include "HarmonicExampleT.hh"
//== NAMESPACES ===============================================================
namespace ACG {
//== IMPLEMENTATION ==========================================================
template<class MeshT>
void
HarmonicExampleT<MeshT>::
compute()
{
// setup simple laplace system
init_laplace_matrix();
gmm::inspect_matrix( laplace_);
// add the integer constraints for the selected vertices
add_integer_constraints();
// init constraints matrix (assume we have at most n_vertices constraints)
gmm::resize( constraints_, mesh_.n_vertices(), mesh_.n_vertices()+1);
// add boundary constraints
gmm::clear(constraints_);
int nconstraints = add_boundary_constraints();
gmm::resize( constraints_, nconstraints, mesh_.n_vertices()+1);
// solve
x_.clear();
x_.resize( mesh_.n_vertices(), 0.0);
rhs_.clear();
rhs_.resize( mesh_.n_vertices(), 0.0);
ACG::ConstrainedSolver cs;
cs.solve( constraints_, laplace_, x_, rhs_, ids_to_round_, 0.0, true, true);
// color the vertices of the mesh
color_mesh();
}
//-----------------------------------------------------------------------------
template<class MeshT>
void
HarmonicExampleT<MeshT>::
init_laplace_matrix()
{
int n = mesh_.n_vertices();
gmm::clear( laplace_);
gmm::resize( laplace_, n, n);
int row = 0;
for( VIter v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it)
{
row = add_laplace_row( v_it.handle(), row);
}
}
//-----------------------------------------------------------------------------
template<class MeshT>
int
HarmonicExampleT<MeshT>::
add_laplace_row( VH _vh, int _row)
{
//// use edge-length "laplacian"
//Point p( mesh_.point( _vh));
//Point q(0,0,0);
//double length = 0.0;
// use simple topological laplacian
for( VOHIter voh_it = mesh_.voh_iter( _vh); voh_it; ++voh_it)
{
VH neigh_vh = mesh_.to_vertex_handle(voh_it.handle());
//q = mesh_.point( neigh_vh);
int neigh_id = neigh_vh.idx();
laplace_( _row, neigh_id) = -1.0;
//double edge_length = (p-q).norm();
//length += edge_length;
//laplace_( _row, neigh_id) = edge_length;
}
laplace_( _row, _vh.idx()) = 1.0*mesh_.valence( _vh);
//laplace_( _row, _vh.idx()) = 1.0*length;
return ++_row;
}
//-----------------------------------------------------------------------------
template<class MeshT>
void
HarmonicExampleT<MeshT>::
add_integer_constraints()
{
ids_to_round_.clear();
for( VIter v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it)
{
if( mesh_.status( v_it.handle()).selected())
{
ids_to_round_.push_back( v_it.handle().idx());
}
}
}
//-----------------------------------------------------------------------------
template<class MeshT>
int
HarmonicExampleT<MeshT>::
add_boundary_constraints()
{
std::vector< int > boundary( mesh_.n_edges(), -1);
int boundaries = 0;
int constraints = 0;
// vertex indices of current boundary and last boundary...
int first_vidx(-1), last_bdry_vidx(-1);
// find boundaries by for every (non marked) boundary edge,
// traverse and mark the whole boundary
for ( EIter e_it = mesh_.edges_begin(); e_it != mesh_.edges_end(); ++e_it )
{
if ( mesh_.is_boundary( e_it.handle() ) && boundary[e_it.handle().idx()] == -1)
{
boundaries++;
// get boundary halfedge
HEH heh_bound( mesh_.halfedge_handle( e_it, 0 ) );
if ( !mesh_.is_boundary( heh_bound ) )
heh_bound = mesh_.halfedge_handle( e_it, 1 );
// fix underdetermindness of laplace system by constraining first boundary to be zero
if ( first_vidx == -1)
{
first_vidx = mesh_.to_vertex_handle( heh_bound).idx();
constraints_(constraints, first_vidx) = 1;
constraints++;
}
// add constraints saying that all vertices on boundary have the same value
// do this by traversing the boundary and setting all vertices equal to the
// first vertex of the boundary
first_vidx = mesh_.to_vertex_handle( heh_bound).idx();
int cur_vidx = -1;
while ( boundary[mesh_.edge_handle( heh_bound ).idx()] == -1 )
{
// tag edge as boundary
boundary[mesh_.edge_handle( heh_bound ).idx()] = boundaries;
heh_bound = mesh_.next_halfedge_handle( heh_bound );
// add equality condition for vertices differnt from the first_vidx
if( cur_vidx != -1)
{
constraints_(constraints, first_vidx) = -1;
constraints_(constraints, cur_vidx) = 1;
constraints++;
}
cur_vidx = mesh_.to_vertex_handle( heh_bound).idx();
}
// just for fun, also relate the boundaries to each other with a difference of 5
if( last_bdry_vidx != -1)
{
constraints_(constraints, first_vidx) = -1;
constraints_(constraints, last_bdry_vidx) = 1;
constraints_(constraints, mesh_.n_vertices()) = 4;
constraints++;
}
last_bdry_vidx = first_vidx;
}
}
return constraints;
}
//-----------------------------------------------------------------------------
template<class MeshT>
void
HarmonicExampleT<MeshT>::
color_mesh()
{
//double vmin = 0.0;
//double vmax = 1.0;
double vmin = (double)*std::min_element( x_.begin(), x_.end());
double vmax = (double)*std::max_element( x_.begin(), x_.end());
// create ColorCoder
ACG::ColorCoder cc( vmin, vmax, false);
VIter v_it = mesh_.vertices_begin();
VIter v_end = mesh_.vertices_end();
for(; v_it != v_end; ++v_it)
{
Scalar v_cur = x_[v_it.handle().idx()];
// clamp
v_cur = std::min(v_cur, vmax);
v_cur = std::max(v_cur, vmin);
//double int_part = floor(v_cur);
//v_cur = v_cur - int_part;
// set vertex color
mesh_.set_color(v_it, cc.color(v_cur));
}
}
//=============================================================================
} // namespace ACG
//=============================================================================
//=============================================================================
//
// CLASS HarmonicExampleT
//
//=============================================================================
#ifndef ACG_HARMONICEXAMPLET_HH
#define ACG_HARMONICEXAMPLET_HH
//== INCLUDES =================================================================
#include <gmm/gmm.h>
#include <OpenMesh/Core/Utils/Property.hh>
#include <OpenMesh/Core/System/omstream.hh>
#include <vector>
#include <string>
#include <iostream>
#include <cfloat> //for FLT_{MIN, MAX}
#include <CoMISo/Utils/StopWatch.hh>
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include <CoMISo/Solver/GMM_Tools.hh>
#include <OpenMesh/Core/Geometry/VectorT.hh>
#include <CoMISo/Solver/ConstrainedSolver.hh>
#include <CoMISo/Utils/ColorCoder.hh>
//== FORWARDDECLARATIONS ======================================================
//== NAMESPACES ===============================================================
namespace ACG {
//== CLASS DEFINITION =========================================================
/** \class HarmonicExampleT HarmonicExampleT.hh <ACG/.../HarmonicExampleT.hh>
Brief Description.
A more elaborate description follows.
*/
template <class MeshT>
class HarmonicExampleT
{
public:
typedef typename MeshT::Scalar Scalar;
typedef typename MeshT::Point Point;
typedef typename OpenMesh::Vec2d Vec2d;
typedef typename MeshT::VertexHandle VH;
typedef typename MeshT::FaceHandle FH;
typedef typename MeshT::EdgeHandle EH;
typedef typename MeshT::HalfedgeHandle HEH;
typedef typename MeshT::FaceIter FIter;
typedef typename MeshT::EdgeIter EIter;
typedef typename MeshT::VertexIter VIter;
typedef typename MeshT::HalfedgeIter HIter;
typedef typename MeshT::FaceFaceIter FFIter;
typedef typename MeshT::FaceVertexIter FVIter;
typedef typename MeshT::VertexFaceIter VFIter;
typedef typename MeshT::VertexEdgeIter VEIter;
typedef typename MeshT::FaceHalfedgeIter FHIter;
typedef typename MeshT::VertexOHalfedgeIter VOHIter;
typedef typename MeshT::VertexIHalfedgeIter VIHIter;
typedef typename MeshT::TexCoord2D TexCoord2D;
typedef unsigned int uint;
typedef typename gmm::linalg_traits< gmm::rsvector< Scalar > > GMMRSTRAIT;
typedef typename gmm::linalg_traits< gmm::wsvector< Scalar > > GMMWSTRAIT;
typedef typename GMMRSTRAIT::iterator GMMColIter;
typedef typename GMMWSTRAIT::iterator wGMMColIter;
typedef typename gmm::wsvector< double > SVectorT;
typedef gmm::linalg_traits<SVectorT>::const_iterator SVIter;
typedef typename gmm::col_matrix< gmm::wsvector< Scalar > > CMatrixT;
typedef typename gmm::row_matrix< gmm::wsvector< Scalar > > RMatrixT;
typedef typename std::vector< Scalar > VectorT;
typedef typename std::vector< int > VectorIT;
typedef gmm::dense_matrix<Scalar> DenseMatrix;
typedef gmm::csc_matrix<double> CSCMatrix;
// typedef ACG::MCSCMatrix MCSCMatrix;
/// Constructor
HarmonicExampleT( MeshT& _mesh) : mesh_(_mesh)
{}
/// Destructor
~HarmonicExampleT() {}
void compute();
private:
// create a simple connectivity-based laplace matrix
void init_laplace_matrix();
int add_laplace_row( VH _vh, int _row);
void add_integer_constraints();
/// adds some constraints to the laplace system.
/// The vertices of each boundary are constrained to the same value.
/// The different boundaries are constrained to differ by e.g. 5
int add_boundary_constraints();
void color_mesh();
// laplace matrix
CMatrixT laplace_;
// solution
std::vector< double > x_;
// right hand side
std::vector< double > rhs_;
// constraints
RMatrixT constraints_;
// integer constraints (indices of variables to be rounded)
std::vector< int > ids_to_round_;
MeshT& mesh_;
};
//=============================================================================
} // namespace ACG
//=============================================================================
#if defined(INCLUDE_TEMPLATES) && !defined(ACG_HARMONICEXAMPLET_C)
#define ACG_HARMONICEXAMPLE_TEMPLATES
#include "HarmonicExampleT.cc"
#endif
//=============================================================================
#endif // ACG_HARMONICEXAMPLET_HH defined
//=============================================================================
#include "ui_HarmonicExampleToolbarBase.hh"
#include <QtGui>
class HarmonicExampleToolbar : public QWidget, public Ui::HarmonicExampleToolbarBase
{
Q_OBJECT
public:
HarmonicExampleToolbar(QWidget * parent = 0)
: QWidget(parent)
{
setupUi(this);
}
};
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>HarmonicExampleToolbarBase</class>
<widget class="QWidget" name="HarmonicExampleToolbarBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>436</width>
<height>959</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="compute_pb">
<property name="text">
<string>Compute</string>
</property>
</widget>
</item>
<item>
<widget class="QTextBrowser" name="textBrowser">
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'DejaVu Sans'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;How does it work?&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;This plugin computes a simple harmonic field on a mesh using the Constrained Mixed-Integer Solver to handle constraints.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;This example plugin came with a test mesh: open_cylinder.off.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;All boundaries of an object will be separated by 5.0 and the vertices on a boundary will all have the same value, this is easily handled by the CoMISo.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Also selected vertices on the mesh will be rounded, try selecting one/none/several vertices.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>903</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
################################################################################
#
################################################################################
include( $$TOPDIR/qmake/all.include )