You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
148 lines
3.5 KiB
148 lines
3.5 KiB
#include <igl/avg_edge_length.h>
|
|
#include <igl/barycenter.h>
|
|
#include <igl/local_basis.h>
|
|
#include <igl/readOFF.h>
|
|
#include <igl/copyleft/comiso/nrosy.h>
|
|
#include <igl/opengl/glfw/Viewer.h>
|
|
#include <igl/PI.h>
|
|
|
|
|
|
// Mesh
|
|
Eigen::MatrixXd V;
|
|
Eigen::MatrixXi F;
|
|
|
|
// Constrained faces id
|
|
Eigen::VectorXi b;
|
|
|
|
// Cosntrained faces representative vector
|
|
Eigen::MatrixXd bc;
|
|
|
|
// Degree of the N-RoSy field
|
|
int N = 4;
|
|
|
|
// Converts a representative vector per face in the full set of vectors that describe
|
|
// an N-RoSy field
|
|
void representative_to_nrosy(
|
|
const Eigen::MatrixXd& V,
|
|
const Eigen::MatrixXi& F,
|
|
const Eigen::MatrixXd& R,
|
|
const int N,
|
|
Eigen::MatrixXd& Y)
|
|
{
|
|
using namespace Eigen;
|
|
using namespace std;
|
|
MatrixXd B1, B2, B3;
|
|
|
|
igl::local_basis(V,F,B1,B2,B3);
|
|
|
|
Y.resize(F.rows()*N,3);
|
|
for (unsigned i=0;i<F.rows();++i)
|
|
{
|
|
double x = R.row(i) * B1.row(i).transpose();
|
|
double y = R.row(i) * B2.row(i).transpose();
|
|
double angle = atan2(y,x);
|
|
|
|
for (unsigned j=0; j<N;++j)
|
|
{
|
|
double anglej = angle + 2*igl::PI*double(j)/double(N);
|
|
double xj = cos(anglej);
|
|
double yj = sin(anglej);
|
|
Y.row(i*N+j) = xj * B1.row(i) + yj * B2.row(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Plots the mesh with an N-RoSy field and its singularities on top
|
|
// The constrained faces (b) are colored in red.
|
|
void plot_mesh_nrosy(
|
|
igl::opengl::glfw::Viewer& viewer,
|
|
Eigen::MatrixXd& V,
|
|
Eigen::MatrixXi& F,
|
|
int N,
|
|
Eigen::MatrixXd& PD1,
|
|
Eigen::VectorXd& S,
|
|
Eigen::VectorXi& b)
|
|
{
|
|
using namespace Eigen;
|
|
using namespace std;
|
|
// Clear the mesh
|
|
viewer.data().clear();
|
|
viewer.data().set_mesh(V,F);
|
|
|
|
// Expand the representative vectors in the full vector set and plot them as lines
|
|
double avg = igl::avg_edge_length(V, F);
|
|
MatrixXd Y;
|
|
representative_to_nrosy(V, F, PD1, N, Y);
|
|
|
|
MatrixXd B;
|
|
igl::barycenter(V,F,B);
|
|
|
|
MatrixXd Be(B.rows()*N,3);
|
|
for(unsigned i=0; i<B.rows();++i)
|
|
for(unsigned j=0; j<N; ++j)
|
|
Be.row(i*N+j) = B.row(i);
|
|
|
|
viewer.data().add_edges(Be,Be+Y*(avg/2),RowVector3d(0,0,1));
|
|
|
|
// Plot the singularities as colored dots (red for positive, blue for negative)
|
|
for (unsigned i=0; i<S.size();++i)
|
|
{
|
|
if (S(i) < -0.001)
|
|
viewer.data().add_points(V.row(i),RowVector3d(0,0,1));
|
|
else if (S(i) > 0.001)
|
|
viewer.data().add_points(V.row(i),RowVector3d(1,0,0));
|
|
}
|
|
|
|
// Highlight in red the constrained faces
|
|
MatrixXd C = MatrixXd::Constant(F.rows(),3,1);
|
|
for (unsigned i=0; i<b.size();++i)
|
|
C.row(b(i)) << 1, 0, 0;
|
|
viewer.data().set_colors(C);
|
|
}
|
|
|
|
// It allows to change the degree of the field when a number is pressed
|
|
bool key_down(igl::opengl::glfw::Viewer& viewer, unsigned char key, int modifier)
|
|
{
|
|
using namespace Eigen;
|
|
using namespace std;
|
|
if (key >= '1' && key <= '9')
|
|
N = key - '0';
|
|
|
|
MatrixXd R;
|
|
VectorXd S;
|
|
|
|
igl::copyleft::comiso::nrosy(V,F,b,bc,VectorXi(),VectorXd(),MatrixXd(),N,0.5,R,S);
|
|
plot_mesh_nrosy(viewer,V,F,N,R,S,b);
|
|
|
|
return false;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
using namespace std;
|
|
using namespace Eigen;
|
|
|
|
// Load a mesh in OFF format
|
|
igl::readOFF(TUTORIAL_SHARED_PATH "/bumpy.off", V, F);
|
|
|
|
// Threshold faces with high anisotropy
|
|
b.resize(1);
|
|
b << 0;
|
|
bc.resize(1,3);
|
|
bc << 1,1,1;
|
|
|
|
igl::opengl::glfw::Viewer viewer;
|
|
|
|
// Interpolate the field and plot
|
|
key_down(viewer, '4', 0);
|
|
|
|
// Plot the mesh
|
|
viewer.data().set_mesh(V, F);
|
|
viewer.callback_key_down = &key_down;
|
|
|
|
// Disable wireframe
|
|
viewer.data().show_lines = false;
|
|
|
|
// Launch the viewer
|
|
viewer.launch();
|
|
}
|
|
|