Create openMVS.build
This commit is contained in:
commit
365aa390ba
1856 files changed
+839085
No files matched your search
@@ -0,0 +1,215 @@
|
||||
/****************************************************************************
|
||||
* VCGLib o o *
|
||||
* Visual and Computer Graphics Library o o *
|
||||
* _ O _ *
|
||||
* Copyright(C) 2017 \/)\/ *
|
||||
* Visual Computing Lab /\/| *
|
||||
* ISTI - Italian National Research Council | *
|
||||
* \ *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
/* Optimizes given UV-mapping with
|
||||
* [ARAP parametrization]
|
||||
* (minimizes area and angle distortions).
|
||||
*
|
||||
* Needs:
|
||||
* (-) per-vertex texture coords
|
||||
* (-) per-vertex flags to fix boundaries
|
||||
* Fixed vertices are the flagged ones.
|
||||
* By default: BORDER or SELECTED verts are fixed.
|
||||
* (use fixedMask parameter to customize)
|
||||
*
|
||||
* Example of usage:
|
||||
* MeshType m;
|
||||
* ...
|
||||
* vcg::tri::UpdateBounding<MeshType>::Box(m);
|
||||
* vcg::tri::UpdateFlags<MeshType>::Clear(m);
|
||||
* vcg::tri::UpdateFlags<MeshType>::VertexBorderFromNone(m);
|
||||
* vcg::tri::OptimizeUV_ARAP(m);
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __VCG_IGL_ARAP_PARAMETRIZATION
|
||||
#define __VCG_IGL_ARAP_PARAMETRIZATION
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <igl/arap.h>
|
||||
#include <vcg/complex/algorithms/mesh_to_matrix.h>
|
||||
#include <vcg/complex/algorithms/clean.h>
|
||||
#include <vcg/complex/algorithms/update/flag.h>
|
||||
#include <wrap/igl/lscm_parametrization.h>
|
||||
|
||||
namespace vcg {
|
||||
namespace tri {
|
||||
|
||||
template<class MeshType>
|
||||
void OptimizeUV_ARAP(
|
||||
MeshType& m,
|
||||
unsigned int iterations = 100,
|
||||
unsigned int fixedMask = MeshType::VertexType::BORDER | MeshType::VertexType::SELECTED,
|
||||
bool generateInitialGuess = true)
|
||||
{
|
||||
|
||||
// check requirements
|
||||
vcg::tri::RequirePerVertexTexCoord(m);
|
||||
vcg::tri::RequirePerVertexFlags (m);
|
||||
vcg::tri::RequireCompactness (m);
|
||||
|
||||
if (m.vert.size() <= 1 || m.face.size() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// build fixed points data
|
||||
size_t nFixed = 0;
|
||||
if (fixedMask != 0)
|
||||
{
|
||||
for (size_t i=0; i<m.vert.size(); i++)
|
||||
{
|
||||
if (m.vert[i].Flags() & fixedMask) nFixed++;
|
||||
}
|
||||
}
|
||||
|
||||
// all fixed, nothing to do? get out to avoid crashes
|
||||
if (nFixed == m.vert.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (generateInitialGuess)
|
||||
{
|
||||
// if not enough vertices are fixed, initialize manually fixed points
|
||||
// else initialize with the provided fixed values
|
||||
InitializeArapWithLSCM(m, (nFixed < 2) ? 0 : fixedMask);
|
||||
}
|
||||
|
||||
Eigen::MatrixXd V;
|
||||
Eigen::MatrixXi F;
|
||||
Eigen::VectorXi b;
|
||||
Eigen::MatrixXd bc;
|
||||
Eigen::MatrixXd V_uv;
|
||||
vcg::tri::MeshToMatrix<MeshType>::GetTriMeshData(m, F, V);
|
||||
vcg::tri::MeshToMatrix<MeshType>::GetUVData(m, V_uv);
|
||||
|
||||
b.resize(nFixed);
|
||||
bc.resize(nFixed,2);
|
||||
for (size_t i=0,k=0; i<m.vert.size(); i++)
|
||||
{
|
||||
if (m.vert[i].Flags() & fixedMask)
|
||||
{
|
||||
b(k) = i;
|
||||
bc(k,0) = m.vert[i].T().P()[0];
|
||||
bc(k,1) = m.vert[i].T().P()[1];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
// Add dynamic regularization to avoid to specify boundary conditions
|
||||
::igl::ARAPData arap_data;
|
||||
arap_data.with_dynamics = true;
|
||||
arap_data.max_iter = iterations;
|
||||
|
||||
// compute ARAP parametrization
|
||||
::igl::arap_precomputation(V, F, 2, b, arap_data);
|
||||
::igl::arap_solve(bc, arap_data, V_uv);
|
||||
|
||||
// copy results back to mesh
|
||||
for (size_t i=0; i<m.vert.size(); i++)
|
||||
{
|
||||
m.vert[i].T().P()[0] = V_uv(i,0);
|
||||
m.vert[i].T().P()[1] = V_uv(i,1);
|
||||
}
|
||||
}
|
||||
|
||||
template <class MeshType>
|
||||
void InitializeArapWithLSCM(MeshType & m, unsigned int fixedMask = 0)
|
||||
{
|
||||
typedef typename MeshType::ScalarType ScalarType;
|
||||
typedef typename MeshType::VertexType::TexCoordType::PointType TexPointType;
|
||||
typedef typename TexPointType::ScalarType TexScalarType;
|
||||
|
||||
if (fixedMask == 0)
|
||||
{
|
||||
// automatically select 2 vertices to fix
|
||||
vcg::tri::UpdateFlags<MeshType>::Clear(m);
|
||||
|
||||
int fixed0, fixed1 = -1;
|
||||
auto p = m.bbox.Center();
|
||||
ScalarType maxDist = -1;
|
||||
for (size_t i=0; i<m.vert.size(); i++)
|
||||
{
|
||||
// farthest point from the center
|
||||
const ScalarType dist =(m.vert[i].cP() - p).Norm();
|
||||
if (dist > maxDist)
|
||||
{
|
||||
fixed0 = i;
|
||||
maxDist = dist;
|
||||
}
|
||||
}
|
||||
maxDist = -1;
|
||||
p = m.vert[fixed0].cP();
|
||||
for (size_t i=0; i<m.vert.size(); i++)
|
||||
{
|
||||
// farthest point from the previous
|
||||
const ScalarType dist =(m.vert[i].cP() - p).Norm();
|
||||
if (dist > maxDist)
|
||||
{
|
||||
fixed1 = i;
|
||||
maxDist = dist;
|
||||
}
|
||||
}
|
||||
|
||||
assert(fixed0 >= 0);
|
||||
assert(fixed1 >= 0);
|
||||
assert(fixed0 != fixed1);
|
||||
|
||||
//then select them
|
||||
m.vert[fixed0].SetS();
|
||||
m.vert[fixed1].SetS();
|
||||
m.vert[fixed0].T().P() = TexPointType(0,0);
|
||||
m.vert[fixed1].T().P() = TexPointType(1,1);
|
||||
|
||||
fixedMask = MeshType::VertexType::SELECTED;
|
||||
}
|
||||
|
||||
vcg::tri::OptimizeUV_LSCM(m, fixedMask);
|
||||
|
||||
// Rescale the parametrization to match the 3D area
|
||||
ScalarType meshArea2D = 0;
|
||||
ScalarType meshArea3D = 0;
|
||||
|
||||
for (size_t i=0; i<m.face.size(); i++)
|
||||
{
|
||||
vcg::Triangle2<TexScalarType> t2(m.face[i].V(0)->T().P(),
|
||||
m.face[i].V(1)->T().P(),
|
||||
m.face[i].V(2)->T().P());
|
||||
meshArea2D += ScalarType(fabs(((t2.P(1) - t2.P(0)) ^ (t2.P(2) - t2.P(0)))/2));
|
||||
meshArea3D += vcg::DoubleArea(m.face[i])/2;
|
||||
}
|
||||
|
||||
ScalarType scaleFact = std::sqrt(meshArea3D / meshArea2D);
|
||||
|
||||
for (size_t i=0; i<m.vert.size(); i++)
|
||||
{
|
||||
TexPointType & UVCoord = m.vert[i].T().P();
|
||||
UVCoord *= scaleFact;
|
||||
}
|
||||
}
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif // __VCG_IGL_ARAP_PARAMETRIZATION
|
||||
@@ -0,0 +1,102 @@
|
||||
/****************************************************************************
|
||||
* VCGLib o o *
|
||||
* Visual and Computer Graphics Library o o *
|
||||
* _ O _ *
|
||||
* Copyright(C) 2014 \/)\/ *
|
||||
* Visual Computing Lab /\/| *
|
||||
* ISTI - Italian National Research Council | *
|
||||
* \ *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
/* Optimizes given UV-mapping with
|
||||
* [Least Square Conformal Maps]
|
||||
* (minimizes angle distrotions).
|
||||
*
|
||||
* Needs:
|
||||
* (-) per-vertex texture coords
|
||||
* (-) some fixed boundary:
|
||||
* Fixed vertices are the flagged ones.
|
||||
* By default: (use fixedMask parameter to customize)
|
||||
* BORDER or SELECTED verts are fixed.
|
||||
*
|
||||
* Example of usage:
|
||||
* MyMesh m;
|
||||
* vcg::tri::UpdateFlags< MyMesh >::VertexBorderFromNone( m );
|
||||
* vcg::tri::OptimizeUV_LSCM( m );
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __VCG_IGL_LEAST_SQUARES_CONFORMAL_MAPS
|
||||
#define __VCG_IGL_LEAST_SQUARES_CONFORMAL_MAPS
|
||||
|
||||
#include <igl/lscm.h>
|
||||
#include <vcg/complex/algorithms/mesh_to_matrix.h>
|
||||
|
||||
namespace vcg{
|
||||
namespace tri{
|
||||
|
||||
template<class MeshType >
|
||||
void OptimizeUV_LSCM( MeshType& m ,
|
||||
unsigned int fixedMask =
|
||||
MeshType::VertexType::BORDER |
|
||||
MeshType::VertexType::SELECTED
|
||||
)
|
||||
{
|
||||
|
||||
// check requirements
|
||||
vcg::tri::VertexVectorHasPerVertexTexCoord( m.vert );
|
||||
vcg::tri::VertexVectorHasPerVertexFlags( m.vert );
|
||||
|
||||
Eigen::MatrixXd V;
|
||||
Eigen::MatrixXi F;
|
||||
Eigen::VectorXi b;
|
||||
Eigen::MatrixXd bc;
|
||||
Eigen::MatrixXd V_uv;
|
||||
|
||||
vcg::tri::MeshToMatrix< MeshType >::GetTriMeshData( m, F, V );
|
||||
|
||||
// build fixed points data
|
||||
size_t nFixed = 0;
|
||||
for (int i=0; i<(int)m.vert.size(); i++) {
|
||||
if (m.vert[i].Flags()&fixedMask) nFixed++;
|
||||
}
|
||||
|
||||
// all fixed, nothing to do? get out to avoid crashes
|
||||
if (nFixed == m.vert.size()) return;
|
||||
|
||||
b.resize(nFixed);
|
||||
bc.resize(nFixed,2);
|
||||
for (int i=0,k=0; i<(int)m.vert.size(); i++) {
|
||||
if (m.vert[i].Flags()&fixedMask) {
|
||||
b(k) = i;
|
||||
bc(k,0) = m.vert[i].T().P()[0];
|
||||
bc(k,1) = m.vert[i].T().P()[1];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
// apply Least Square Conformal Maps
|
||||
::igl::lscm(V,F,b,bc,V_uv);
|
||||
|
||||
// copy results back to mesh
|
||||
for (int i=0; i<(int)m.vert.size(); i++) {
|
||||
m.vert[i].T().P()[0] = V_uv(i,0);
|
||||
m.vert[i].T().P()[1] = V_uv(i,1);
|
||||
}
|
||||
}
|
||||
|
||||
}} // namespaces
|
||||
#endif
|
||||
@@ -0,0 +1,358 @@
|
||||
/****************************************************************************
|
||||
* VCGLib o o *
|
||||
* Visual and Computer Graphics Library o o *
|
||||
* _ O _ *
|
||||
* Copyright(C) 2014 \/)\/ *
|
||||
* Visual Computing Lab /\/| *
|
||||
* ISTI - Italian National Research Council | *
|
||||
* \ *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __MIQ_PARAMETRIZATION_H
|
||||
#define __MIQ_PARAMETRIZATION_H
|
||||
|
||||
//igl stuff
|
||||
#include <igl/cross_field_missmatch.h>
|
||||
#include <igl/line_field_missmatch.h>
|
||||
#include <igl/comb_line_field.h>
|
||||
#include <igl/cut_mesh_from_singularities.h>
|
||||
#include <igl/find_cross_field_singularities.h>
|
||||
#include <igl/compute_frame_field_bisectors.h>
|
||||
#include <igl/copyleft/comiso/miq.h>
|
||||
#include <vcg/complex/algorithms/parametrization/uv_utils.h>
|
||||
#include <vcg/complex/algorithms/mesh_to_matrix.h>
|
||||
|
||||
namespace vcg {
|
||||
namespace tri {
|
||||
template < class MeshType> // Classe templatata su Tipo Mesh
|
||||
class MiQParametrizer
|
||||
{
|
||||
|
||||
typedef typename MeshType::CoordType CoordType;
|
||||
typedef typename MeshType::VertexType VertexType;
|
||||
typedef typename MeshType::FaceType FaceType;
|
||||
typedef typename MeshType::ScalarType ScalarType;
|
||||
typedef typename MeshType::VertexType PolyVertexType;
|
||||
|
||||
public:
|
||||
struct MIQParameters
|
||||
{
|
||||
//the gradient of the parametrization 1 is the bb diagonal, as big is the gradient as small are the quads
|
||||
double gradient;
|
||||
//do the rounding or not across cuts... set to true to get a quadrangulation
|
||||
bool doRound;
|
||||
//do the round at once for each stiffness iteration or do it gradually.. gradually is more stable but much mor slow
|
||||
bool directRound;
|
||||
//the stiffness increment for ach iteration
|
||||
double stiffness;
|
||||
//the maximum number ofstiffness iteration to avoid folds
|
||||
int stiffness_iter;
|
||||
//local iteration to round integer variables ofr each stiffness round
|
||||
int local_iter;
|
||||
//this bool multiply the gradiens U or V separately times a constant to make hexagons
|
||||
bool hexaLine;
|
||||
//the threshold of normal dot product to consider a crease
|
||||
double crease_thr;
|
||||
//number of 90° rotation independence (4 for quad meshing, 2 to obtain a quad meshing for hexagonalization)
|
||||
int Ndir;
|
||||
//round or not the singularities
|
||||
bool round_singularities;
|
||||
//use the crease edges as feature or not
|
||||
bool crease_as_feature;
|
||||
//true if roound selected vert
|
||||
bool round_selected;
|
||||
//the anisotropy in MIQ sense (see paper)
|
||||
double miqAnisotropy;
|
||||
|
||||
MIQParameters()
|
||||
{
|
||||
gradient=80;
|
||||
doRound=true;
|
||||
directRound=true;
|
||||
round_singularities=true;
|
||||
crease_as_feature=false;
|
||||
round_selected=true;
|
||||
stiffness=5;
|
||||
stiffness_iter=10;
|
||||
local_iter=5;
|
||||
Ndir=4;
|
||||
crease_thr=0.2;
|
||||
hexaLine=false;
|
||||
miqAnisotropy=1;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void GetFeatureLines(MeshType &trimesh,
|
||||
std::vector<std::vector<int> > &feature_lines)
|
||||
{
|
||||
feature_lines.clear();
|
||||
|
||||
for (size_t i=0;i<trimesh.face.size();i++)
|
||||
{
|
||||
for (int j=0;j<3;j++)
|
||||
{
|
||||
//if (!trimesh.face[i].IsB(j))continue;
|
||||
//if (!trimesh.face[i].IsCrease(j))continue;
|
||||
if (!trimesh.face[i].IsFaceEdgeS(j))continue;
|
||||
|
||||
feature_lines.push_back(std::vector<int>());
|
||||
feature_lines.back().push_back(i);
|
||||
feature_lines.back().push_back(j);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
|
||||
|
||||
static void CrossFieldParam(MeshType &trimesh,
|
||||
MIQParameters &MiqP)
|
||||
{
|
||||
|
||||
Eigen::MatrixXi F;
|
||||
Eigen::MatrixXd V;
|
||||
vcg::tri::MeshToMatrix<MeshType>::GetTriMeshData(trimesh,F,V);
|
||||
|
||||
//then get the principal directions
|
||||
Eigen::MatrixXd X1,X2;
|
||||
X1=Eigen::MatrixXd(trimesh.FN(), 3);
|
||||
for (size_t i=0;i<trimesh.face.size();i++)
|
||||
{
|
||||
CoordType Dir1=trimesh.face[i].PD1();
|
||||
Dir1.Normalize();
|
||||
for (int j=0;j<3;j++)
|
||||
{
|
||||
X1(i,j)=Dir1[j];
|
||||
}
|
||||
}
|
||||
|
||||
Eigen::MatrixXd B1,B2,B3;
|
||||
igl::local_basis(V,F,B1,B2,B3);
|
||||
X2 = igl::rotate_vectors(X1, Eigen::VectorXd::Constant(1,M_PI/2), B1, B2);
|
||||
|
||||
Eigen::MatrixXd UV;
|
||||
Eigen::MatrixXi FUV;
|
||||
|
||||
//ScalarType gradsize=trimesh.bbox.Diag()*2;
|
||||
|
||||
std::vector<std::vector<int> > hard_features;
|
||||
|
||||
if (MiqP.crease_as_feature)
|
||||
GetFeatureLines(trimesh,hard_features);
|
||||
|
||||
std::vector<int> extra_round;
|
||||
|
||||
if (MiqP.round_selected)
|
||||
{
|
||||
for (int i=0;i<trimesh.vert.size();i++)
|
||||
{
|
||||
if (!trimesh.vert[i].IsS())continue;
|
||||
extra_round.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
igl::copyleft::comiso::miq(V,F,X1,X2,UV,FUV,MiqP.gradient,MiqP.stiffness,MiqP.directRound,
|
||||
MiqP.stiffness_iter,MiqP.local_iter,MiqP.doRound,MiqP.round_singularities,
|
||||
extra_round,hard_features,MiqP.miqAnisotropy);
|
||||
|
||||
// then copy UV
|
||||
for (size_t i=0;i<trimesh.face.size();i++)
|
||||
{
|
||||
for (int j=0;j<3;j++)
|
||||
{
|
||||
int index=FUV(i,j);
|
||||
trimesh.face[i].WT(j).P()[0]=UV(index,0);
|
||||
trimesh.face[i].WT(j).P()[1]=UV(index,1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void LineFieldParam(MeshType &trimesh,
|
||||
MIQParameters &MiqP)
|
||||
{
|
||||
|
||||
Eigen::MatrixXi F;
|
||||
Eigen::MatrixXd V;
|
||||
vcg::tri::MeshToMatrix<MeshType>::GetTriMeshData(trimesh,F,V);
|
||||
|
||||
//then get the principal directions
|
||||
Eigen::MatrixXd X1,X2;
|
||||
X1=Eigen::MatrixXd(trimesh.FN(), 3);
|
||||
for (size_t i=0;i<trimesh.face.size();i++)
|
||||
{
|
||||
CoordType Dir1=trimesh.face[i].PD1();
|
||||
Dir1.Normalize();
|
||||
for (int j=0;j<3;j++)
|
||||
{
|
||||
X1(i,j)=Dir1[j];
|
||||
}
|
||||
}
|
||||
|
||||
Eigen::MatrixXd B1,B2,B3;
|
||||
igl::local_basis(V,F,B1,B2,B3);
|
||||
X2 = igl::rotate_vectors(X1, Eigen::VectorXd::Constant(1,M_PI/2), B1, B2);
|
||||
|
||||
// Bisector field
|
||||
Eigen::MatrixXd BIS1, BIS2;
|
||||
|
||||
// Combed bisector
|
||||
Eigen::MatrixXd BIS1_combed, BIS2_combed;
|
||||
|
||||
// Per-corner, integer mismatches
|
||||
Eigen::MatrixXi MMatch;
|
||||
|
||||
// Field singularities
|
||||
Eigen::VectorXi isSingularity, singularityIndex;
|
||||
|
||||
// Per corner seams
|
||||
Eigen::MatrixXi Seams;
|
||||
|
||||
// Combed field
|
||||
Eigen::MatrixXd X1_combed, X2_combed;
|
||||
|
||||
|
||||
// Global parametrization (with seams)
|
||||
Eigen::MatrixXd UV_seams;
|
||||
Eigen::MatrixXi FUV_seams;
|
||||
|
||||
// Global parametrization
|
||||
Eigen::MatrixXd UV;
|
||||
Eigen::MatrixXi FUV;
|
||||
|
||||
// Always work on the bisectors, it is more general
|
||||
igl::compute_frame_field_bisectors(V, F, X1, X2, BIS1, BIS2);
|
||||
|
||||
// Comb the field, implicitly defining the seams
|
||||
igl::comb_line_field(V, F, BIS1, BIS1_combed);
|
||||
igl::local_basis(V,F,B1,B2,B3);
|
||||
BIS2_combed = igl::rotate_vectors(BIS1_combed, Eigen::VectorXd::Constant(1,M_PI/2), B1, B2);
|
||||
|
||||
// Find the integer mismatches
|
||||
igl::line_field_missmatch(V, F, BIS1_combed, true, MMatch);
|
||||
|
||||
// Find the singularities
|
||||
igl::find_cross_field_singularities(V, F, MMatch, isSingularity, singularityIndex);
|
||||
|
||||
// Cut the mesh, duplicating all vertices on the seams
|
||||
//igl::cut_mesh_from_singularities(V, F, MMatch, isSingularity, singularityIndex, Seams);
|
||||
igl::cut_mesh_from_singularities(V, F, MMatch,Seams);
|
||||
|
||||
// Comb the frame-field accordingly
|
||||
igl::comb_frame_field(V, F, X1, X2, BIS1_combed, BIS2_combed, X1_combed, X2_combed);
|
||||
|
||||
std::vector<std::vector<int> > hard_features;
|
||||
|
||||
|
||||
std::vector<int> extra_round;
|
||||
//collect extra vertex selected that need to be rounded
|
||||
if (MiqP.round_selected)
|
||||
{
|
||||
for (int i=0;i<trimesh.vert.size();i++)
|
||||
{
|
||||
if (!trimesh.vert[i].IsS())continue;
|
||||
extra_round.push_back(i);
|
||||
}
|
||||
}
|
||||
if (MiqP.crease_as_feature)
|
||||
GetFeatureLines(trimesh,hard_features);
|
||||
|
||||
//scale gradient if needed
|
||||
ScalarType sqrt3=1.732050807568877;
|
||||
|
||||
ScalarType GradX=0.5;
|
||||
ScalarType GradY=1;
|
||||
|
||||
if (MiqP.hexaLine)
|
||||
{
|
||||
for (int i=0;i<X1_combed.rows();i++)
|
||||
{
|
||||
X1_combed(i)*=GradX;//*ScaleFact;
|
||||
X2_combed(i)*=GradY;//*ScaleFact;
|
||||
}
|
||||
}
|
||||
|
||||
// igl::miq(V,F,X1_combed,X2_combed,BIS1_combed,BIS2_combed,
|
||||
// MMatch,isSingularity,singularityIndex,Seams,
|
||||
// UV,FUV,MiqP.gradient,MiqP.stiffness,MiqP.directRound,
|
||||
// MiqP.stiffness_iter,MiqP.local_iter,MiqP.doRound,MiqP.round_singularities,extra_round,hard_features);
|
||||
igl::copyleft::comiso::miq(V,F,X1_combed,X2_combed,
|
||||
UV,FUV,MiqP.gradient,MiqP.stiffness,MiqP.directRound,
|
||||
MiqP.stiffness_iter,MiqP.local_iter,MiqP.doRound,MiqP.round_singularities,extra_round,hard_features);
|
||||
|
||||
// then copy UV
|
||||
for (size_t i=0;i<trimesh.face.size();i++)
|
||||
{
|
||||
for (int j=0;j<3;j++)
|
||||
{
|
||||
int index=FUV(i,j);
|
||||
trimesh.face[i].WT(j).P()[0]=UV(index,0);//*4;
|
||||
trimesh.face[i].WT(j).P()[1]=UV(index,1);//*2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
static void SetCreases(MeshType & mesh,
|
||||
const ScalarType &thr=0.2,
|
||||
bool setBorder=true)
|
||||
{
|
||||
for (size_t i=0;i<mesh.face.size();i++)
|
||||
for (int j=0;j<mesh.face[i].VN();j++)
|
||||
{
|
||||
FaceType *f0=&mesh.face[i];
|
||||
//f0->ClearCrease(j);
|
||||
f0->ClearFaceEdgeS(j);
|
||||
}
|
||||
|
||||
|
||||
for (size_t i=0;i<mesh.face.size();i++)
|
||||
for (int j=0;j<mesh.face[i].VN();j++)
|
||||
{
|
||||
FaceType *f0=&mesh.face[i];
|
||||
FaceType *f1=f0->FFp(j);
|
||||
|
||||
//if (f0==f1){f0->SetCrease(j);continue;}
|
||||
if (f0==f1){f0->SetFaceEdgeS(j);continue;}
|
||||
|
||||
CoordType N0=f0->N();
|
||||
CoordType N1=f1->N();
|
||||
if ((N0*N1)>thr)continue;
|
||||
//f0->SetCrease(j);
|
||||
f0->SetFaceEdgeS(j);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void MIQParametrize(MeshType &trimesh,
|
||||
MIQParameters &MiqP)
|
||||
{
|
||||
// if (MiqP.crease_as_feature)
|
||||
// SetCreases(trimesh,MiqP.crease_thr);
|
||||
|
||||
if (MiqP.Ndir==4)
|
||||
CrossFieldParam(trimesh,MiqP);
|
||||
else
|
||||
LineFieldParam(trimesh,MiqP);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace tri
|
||||
} // end namespace vcg
|
||||
#endif // VORO_CLUSTER_H
|
||||
@@ -0,0 +1,64 @@
|
||||
/****************************************************************************
|
||||
* VCGLib o o *
|
||||
* Visual and Computer Graphics Library o o *
|
||||
* _ O _ *
|
||||
* Copyright(C) 2004-2009 \/)\/ *
|
||||
* Visual Computing Lab /\/| *
|
||||
* ISTI - Italian National Research Council | *
|
||||
* \ *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
#include<vcg/complex/complex.h>
|
||||
#include<vcg/complex/algorithms/create/platonic.h>
|
||||
|
||||
#include<wrap/io_trimesh/import_ply.h>
|
||||
#include<wrap/io_trimesh/export_ply.h>
|
||||
#include<vcg/complex/algorithms/create/platonic.h>
|
||||
#include<wrap/igl/smooth_field.h>
|
||||
|
||||
using namespace vcg;
|
||||
using namespace std;
|
||||
|
||||
class MyEdge;
|
||||
class MyFace;
|
||||
class MyVertex;
|
||||
struct MyUsedTypes : public UsedTypes< Use<MyVertex> ::AsVertexType,
|
||||
Use<MyEdge> ::AsEdgeType,
|
||||
Use<MyFace> ::AsFaceType>{};
|
||||
|
||||
class MyVertex : public Vertex<MyUsedTypes, vertex::Coord3f, vertex::Normal3f, vertex::VFAdj, vertex::Qualityf, vertex::Color4b, vertex::BitFlags, vertex::CurvatureDirf >{};
|
||||
class MyFace : public Face< MyUsedTypes, face::VertexRef, face::Normal3f, face::BitFlags, face::FFAdj, face::VFAdj, face::CurvatureDirf, face::Qualityf, face::Color4b> {};
|
||||
class MyEdge : public Edge< MyUsedTypes>{};
|
||||
class MyMesh : public tri::TriMesh< std::vector<MyVertex>, std::vector<MyFace> , vector<MyEdge> > {};
|
||||
|
||||
|
||||
int main( int argc, char **argv )
|
||||
{
|
||||
MyMesh m;
|
||||
tri::Hexahedron(m);
|
||||
tri::UpdateTopology<MyMesh>::FaceFace(m);
|
||||
tri::UpdateFlags<MyMesh>::FaceBorderFromFF(m);
|
||||
for(int i=0;i<3;++i)
|
||||
tri::Refine<MyMesh, tri::MidPoint<MyMesh> >(m,tri::MidPoint<MyMesh>(&m));
|
||||
|
||||
tri::UpdateNormal<MyMesh>::PerVertexNormalized(m);
|
||||
tri::Smooth<MyMesh>::VertexCoordLaplacian(m,3);
|
||||
tri::FieldSmoother<MyMesh>::InitByCurvature(m,2);
|
||||
tri::FieldSmoother<MyMesh>::SmoothParam par;
|
||||
|
||||
tri::FieldSmoother<MyMesh>::SmoothDirections(m,par);
|
||||
tri::io::ExporterPLY<MyMesh>::Save(m,"Full.ply",tri::io::Mask::IOM_VERTCOLOR|tri::io::Mask::IOM_WEDGTEXCOORD );
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
DEPENDPATH += . ../../../../..
|
||||
INCLUDEPATH += . ../../../.. ../../../../eigenlib
|
||||
|
||||
CONFIG += console c++11
|
||||
TEMPLATE = app
|
||||
# Mac specific Config required to avoid to make application bundles
|
||||
CONFIG -= app_bundle
|
||||
|
||||
QMAKE_CXXFLAGS += -std=c++11
|
||||
TARGET = trimesh_field_smoothing
|
||||
SOURCES += trimesh_field_smoothing.cpp ../../../ply/plylib.cpp
|
||||
@@ -0,0 +1,550 @@
|
||||
/****************************************************************************
|
||||
* VCGLib o o *
|
||||
* Visual and Computer Graphics Library o o *
|
||||
* _ O _ *
|
||||
* Copyright(C) 2014 \/)\/ *
|
||||
* Visual Computing Lab /\/| *
|
||||
* ISTI - Italian National Research Council | *
|
||||
* \ *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef SMOOTHER_FIELD_H
|
||||
#define SMOOTHER_FIELD_H
|
||||
|
||||
//eigen stuff
|
||||
#include <Eigen/Sparse>
|
||||
|
||||
//vcg stuff
|
||||
#include <vcg/complex/algorithms/update/color.h>
|
||||
#include <vcg/complex/algorithms/update/quality.h>
|
||||
#include <vcg/complex/algorithms/parametrization/tangent_field_operators.h>
|
||||
#include <vcg/complex/algorithms/mesh_to_matrix.h>
|
||||
|
||||
//igl related stuff
|
||||
|
||||
#include <igl/n_polyvector.h>
|
||||
#include <igl/principal_curvature.h>
|
||||
#include <igl/igl_inline.h>
|
||||
|
||||
#ifdef COMISO_FIELD
|
||||
#include <igl/copyleft/comiso/nrosy.h>
|
||||
#endif
|
||||
|
||||
namespace vcg {
|
||||
namespace tri {
|
||||
|
||||
enum SmoothMethod{SMMiq,SMNPoly,SMIterative};
|
||||
|
||||
template <class MeshType>
|
||||
class FieldSmoother
|
||||
{
|
||||
typedef typename MeshType::FaceType FaceType;
|
||||
typedef typename MeshType::VertexType VertexType;
|
||||
typedef typename MeshType::ScalarType ScalarType;
|
||||
typedef typename MeshType::CoordType CoordType;
|
||||
|
||||
|
||||
static void InitQualityByAnisotropyDir(MeshType &mesh)
|
||||
{
|
||||
ScalarType minV=0.00001;
|
||||
std::vector<ScalarType> QVal;
|
||||
for (size_t i=0;i<mesh.vert.size();i++)
|
||||
{
|
||||
ScalarType N1=fabs(mesh.vert[i].K1());
|
||||
ScalarType N2=fabs(mesh.vert[i].K2());
|
||||
QVal.push_back(N1);
|
||||
QVal.push_back(N2);
|
||||
}
|
||||
|
||||
std::sort(QVal.begin(),QVal.end());
|
||||
int percUp=int(floor(QVal.size()*0.95+0.5));
|
||||
ScalarType trimUp=QVal[percUp];
|
||||
|
||||
for (size_t i=0;i<mesh.vert.size();i++)
|
||||
{
|
||||
ScalarType N1=(mesh.vert[i].K1());
|
||||
ScalarType N2=(mesh.vert[i].K2());
|
||||
|
||||
ScalarType NMax=std::max(N1,N2)/trimUp;
|
||||
ScalarType NMin=std::min(N1,N2)/trimUp;
|
||||
|
||||
if (NMax>1)NMax=1;
|
||||
if (NMax<-1)NMax=-1;
|
||||
|
||||
if (NMin>1)NMin=1;
|
||||
if (NMin<-1)NMin=-1;
|
||||
|
||||
ScalarType CurvAni=(NMax-NMin)/2;
|
||||
CurvAni=std::max(CurvAni,minV);
|
||||
mesh.vert[i].Q()=CurvAni;
|
||||
}
|
||||
vcg::tri::UpdateQuality<MeshType>::FaceFromVertex(mesh);
|
||||
}
|
||||
|
||||
static void SetEdgeDirection(FaceType *f,int edge)
|
||||
{
|
||||
CoordType dir=f->P0(edge)-f->P1(edge);
|
||||
dir.Normalize();
|
||||
ScalarType prod1=fabs(dir*f->PD1());
|
||||
ScalarType prod2=fabs(dir*f->PD2());
|
||||
if (prod1>prod2)
|
||||
{
|
||||
f->PD1()=dir;
|
||||
f->PD2()=f->N()^dir;
|
||||
}else
|
||||
{
|
||||
f->PD2()=dir;
|
||||
f->PD1()=f->N()^dir;
|
||||
}
|
||||
}
|
||||
|
||||
static void AddSharpEdgesConstraints(MeshType & mesh,
|
||||
const ScalarType &thr=0.2)
|
||||
{
|
||||
for (size_t i=0;i<mesh.face.size();i++)
|
||||
for (int j=0;j<mesh.face[i].VN();j++)
|
||||
{
|
||||
FaceType *f0=&mesh.face[i];
|
||||
FaceType *f1=f0->FFp(j);
|
||||
if (f0==f1)continue;
|
||||
CoordType N0=f0->N();
|
||||
CoordType N1=f1->N();
|
||||
if ((N0*N1)>thr)continue;
|
||||
SetEdgeDirection(f0,j);
|
||||
f0->SetS();
|
||||
}
|
||||
}
|
||||
|
||||
static void AddBorderConstraints(MeshType & mesh)
|
||||
{
|
||||
for (size_t i=0;i<mesh.face.size();i++)
|
||||
for (int j=0;j<mesh.face[i].VN();j++)
|
||||
{
|
||||
FaceType *f0=&mesh.face[i];
|
||||
FaceType *f1=f0->FFp(j);
|
||||
assert(f1!=NULL);
|
||||
if (f0!=f1)continue;
|
||||
SetEdgeDirection(f0,j);
|
||||
f0->SetS();
|
||||
}
|
||||
}
|
||||
|
||||
static void AddCurvatureConstraints(MeshType & mesh,const ScalarType &thr=0.5)
|
||||
{
|
||||
for (size_t i=0;i<mesh.face.size();i++)
|
||||
if (mesh.face[i].Q()>thr)mesh.face[i].SetS();
|
||||
}
|
||||
|
||||
//hard constraints have selected face
|
||||
static void CollectHardConstraints( MeshType & mesh,
|
||||
Eigen::VectorXi &HardI,
|
||||
Eigen::MatrixXd &HardD,
|
||||
SmoothMethod SMethod,
|
||||
int Ndir)
|
||||
{
|
||||
//count number of hard constraints
|
||||
int numS=vcg::tri::UpdateSelection<MeshType>::FaceCount(mesh);
|
||||
HardI=Eigen::MatrixXi(numS,1);
|
||||
if ((Ndir==2)||(SMethod==SMMiq))
|
||||
HardD=Eigen::MatrixXd(numS,3);
|
||||
else
|
||||
HardD=Eigen::MatrixXd(numS,6);
|
||||
//then update them
|
||||
int curr_index=0;
|
||||
for (size_t i=0;i<mesh.face.size();i++)
|
||||
{
|
||||
if (!mesh.face[i].IsS())continue;
|
||||
|
||||
CoordType dir=mesh.face[i].PD1();
|
||||
dir.Normalize();
|
||||
|
||||
HardI(curr_index,0)=i;
|
||||
|
||||
HardD(curr_index,0)=dir.X();
|
||||
HardD(curr_index,1)=dir.Y();
|
||||
HardD(curr_index,2)=dir.Z();
|
||||
if ((Ndir==4)&&(SMethod==SMNPoly))
|
||||
{
|
||||
dir=mesh.face[i].PD2();
|
||||
HardD(curr_index,3)=dir.X();
|
||||
HardD(curr_index,4)=dir.Y();
|
||||
HardD(curr_index,5)=dir.Z();
|
||||
}
|
||||
curr_index++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//hard constraints have selected face
|
||||
static void CollectSoftConstraints( MeshType & mesh,
|
||||
Eigen::VectorXi &SoftI,
|
||||
Eigen::MatrixXd &SoftD,
|
||||
Eigen::VectorXd &SoftW)
|
||||
{
|
||||
//count number of soft constraints
|
||||
int numS=vcg::tri::UpdateSelection<MeshType>::FaceCount(mesh);
|
||||
numS=mesh.fn-numS;
|
||||
//allocate eigen matrix
|
||||
SoftI=Eigen::MatrixXi(numS,1);
|
||||
SoftD=Eigen::MatrixXd(numS,3);
|
||||
SoftW=Eigen::MatrixXd(numS,1);
|
||||
|
||||
//then update them
|
||||
int curr_index=0;
|
||||
for (size_t i=0;i<mesh.face.size();i++)
|
||||
{
|
||||
if (mesh.face[i].IsS())continue;
|
||||
|
||||
CoordType dir=mesh.face[i].PD1();
|
||||
dir.Normalize();
|
||||
|
||||
SoftI(curr_index,0)=i;
|
||||
|
||||
SoftD(curr_index,0)=dir.X();
|
||||
SoftD(curr_index,1)=dir.Y();
|
||||
SoftD(curr_index,2)=dir.Z();
|
||||
|
||||
SoftW(curr_index,0)=mesh.face[i].Q();
|
||||
curr_index++;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void SmoothMIQ(MeshType &mesh,
|
||||
Eigen::VectorXi &HardI, //hard constraints index
|
||||
Eigen::MatrixXd &HardD, //hard directions
|
||||
Eigen::VectorXi &SoftI, //soft constraints
|
||||
Eigen::MatrixXd &SoftD, //weight of soft constraints
|
||||
Eigen::VectorXd &SoftW, //soft directions
|
||||
ScalarType alpha_soft,
|
||||
int Ndir)
|
||||
{
|
||||
#ifdef COMISO_FIELD
|
||||
assert((Ndir==2)||(Ndir==4));
|
||||
Eigen::MatrixXi F;
|
||||
typename vcg::tri::MeshToMatrix<MeshType>::MatrixXm Vf;
|
||||
|
||||
MeshToMatrix<MeshType>::GetTriMeshData(mesh,F,Vf);
|
||||
Eigen::MatrixXd V = Vf.template cast<double>();
|
||||
|
||||
Eigen::MatrixXd output_field;
|
||||
Eigen::VectorXd output_sing;
|
||||
|
||||
igl::copyleft::comiso::nrosy(V,F,HardI,HardD,SoftI,SoftW,SoftD,Ndir,alpha_soft,output_field,output_sing);
|
||||
|
||||
//finally update the principal directions
|
||||
for (size_t i=0;i<mesh.face.size();i++)
|
||||
{
|
||||
CoordType dir1;
|
||||
dir1[0]=output_field(i,0);
|
||||
dir1[1]=output_field(i,1);
|
||||
dir1[2]=output_field(i,2);
|
||||
|
||||
dir1.Normalize();
|
||||
CoordType dir2=mesh.face[i].N()^dir1;
|
||||
dir2.Normalize();
|
||||
|
||||
ScalarType Norm1=mesh.face[i].PD1().Norm();
|
||||
ScalarType Norm2=mesh.face[i].PD2().Norm();
|
||||
|
||||
mesh.face[i].PD1()=dir1*Norm1;
|
||||
mesh.face[i].PD2()=dir2*Norm2;
|
||||
}
|
||||
#else
|
||||
(void)mesh;
|
||||
(void)HardI;
|
||||
(void)HardD;
|
||||
(void)SoftI;
|
||||
(void)SoftD;
|
||||
(void)SoftW;
|
||||
(void)alpha_soft;
|
||||
(void)Ndir;
|
||||
assert(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void SmoothNPoly(MeshType &mesh,
|
||||
Eigen::VectorXi &HardI, //hard constraints index
|
||||
Eigen::MatrixXd &HardD, //hard directions
|
||||
int Ndir)
|
||||
{
|
||||
assert((Ndir==2)||(Ndir==4));
|
||||
|
||||
Eigen::MatrixXi F;
|
||||
typename vcg::tri::MeshToMatrix<MeshType>::MatrixXm Vf;
|
||||
//Eigen::MatrixXd V;
|
||||
|
||||
MeshToMatrix<MeshType>::GetTriMeshData(mesh,F,Vf);
|
||||
//then cast
|
||||
Eigen::MatrixXd V = Vf.template cast<double>();
|
||||
Eigen::MatrixXd output_field;
|
||||
//Eigen::VectorXd output_sing;
|
||||
|
||||
igl::n_polyvector(V,F,HardI,HardD,output_field);
|
||||
|
||||
//finally update the principal directions
|
||||
for (size_t i=0;i<mesh.face.size();i++)
|
||||
{
|
||||
CoordType dir1;
|
||||
dir1[0]=output_field(i,0);
|
||||
dir1[1]=output_field(i,1);
|
||||
dir1[2]=output_field(i,2);
|
||||
|
||||
dir1.Normalize();
|
||||
CoordType dir2=mesh.face[i].N()^dir1;
|
||||
dir2.Normalize();
|
||||
|
||||
ScalarType Norm1=mesh.face[i].PD1().Norm();
|
||||
ScalarType Norm2=mesh.face[i].PD2().Norm();
|
||||
|
||||
mesh.face[i].PD1()=dir1*Norm1;
|
||||
mesh.face[i].PD2()=dir2*Norm2;
|
||||
}
|
||||
}
|
||||
|
||||
static void PickRandomDir(MeshType &mesh,
|
||||
int &indexF,
|
||||
CoordType &Dir)
|
||||
{
|
||||
indexF=rand()%mesh.fn;
|
||||
FaceType *currF=&mesh.face[indexF];
|
||||
CoordType dirN=currF->N();
|
||||
dirN.Normalize();
|
||||
Dir=CoordType(1,0,0);
|
||||
if (fabs(Dir*dirN)>0.9)
|
||||
Dir=CoordType(0,1,0);
|
||||
if (fabs(Dir*dirN)>0.9)
|
||||
Dir=CoordType(0,0,1);
|
||||
|
||||
Dir=dirN^Dir;
|
||||
Dir.Normalize();
|
||||
}
|
||||
|
||||
|
||||
static void GloballyOrient(MeshType &mesh)
|
||||
{
|
||||
vcg::tri::CrossField<MeshType>::MakeDirectionFaceCoherent(mesh,true);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
struct SmoothParam
|
||||
{
|
||||
//the 90° rotation independence while smoothing the direction field
|
||||
int Ndir;
|
||||
//the weight of curvature if doing the smoothing keeping the field close to the original one
|
||||
ScalarType alpha_curv;
|
||||
//align the field to border or not
|
||||
bool align_borders;
|
||||
//threshold to consider some edge as sharp feature and to use as hard constraint (0, not use)
|
||||
ScalarType sharp_thr;
|
||||
//threshold to consider some edge as high curvature anisotropyand to use as hard constraint (0, not use)
|
||||
ScalarType curv_thr;
|
||||
//the method used to smooth MIQ or "Designing N-PolyVector Fields with Complex Polynomials"
|
||||
SmoothMethod SmoothM;
|
||||
//the number of faces of the ring used ot esteem the curvature
|
||||
int curvRing;
|
||||
//this are additional hard constraints
|
||||
std::vector<std::pair<int,CoordType> > AddConstr;
|
||||
//the number of iteration in case of iterative method
|
||||
size_t IteN;
|
||||
|
||||
//initialize with curvature or not
|
||||
SmoothParam()
|
||||
{
|
||||
Ndir=4;
|
||||
curvRing=3;
|
||||
alpha_curv=0.0;
|
||||
align_borders=false;
|
||||
SmoothM=SMMiq;
|
||||
sharp_thr=0.0;
|
||||
curv_thr=0.4;
|
||||
IteN=20;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static void InitByCurvature(MeshType & mesh,
|
||||
unsigned Nring,
|
||||
bool UpdateFaces=true)
|
||||
{
|
||||
|
||||
tri::RequirePerVertexCurvatureDir(mesh);
|
||||
|
||||
Eigen::MatrixXi F;
|
||||
typename vcg::tri::MeshToMatrix<MeshType>::MatrixXm Vf;
|
||||
|
||||
Eigen::MatrixXd PD1,PD2,PV1,PV2;
|
||||
MeshToMatrix<MeshType>::GetTriMeshData(mesh,F,Vf);
|
||||
Eigen::MatrixXd V = Vf.template cast<double>();
|
||||
|
||||
igl::principal_curvature(V,F,PD1,PD2,PV1,PV2,Nring,true);
|
||||
|
||||
//then copy curvature per vertex
|
||||
for (size_t i=0;i<mesh.vert.size();i++)
|
||||
{
|
||||
mesh.vert[i].PD1()=CoordType(PD1(i,0),PD1(i,1),PD1(i,2));
|
||||
mesh.vert[i].PD2()=CoordType(PD2(i,0),PD2(i,1),PD2(i,2));
|
||||
mesh.vert[i].K1()=PV1(i,0);
|
||||
mesh.vert[i].K2()=PV2(i,0);
|
||||
}
|
||||
if (!UpdateFaces)return;
|
||||
vcg::tri::CrossField<MeshType>::SetFaceCrossVectorFromVert(mesh);
|
||||
InitQualityByAnisotropyDir(mesh);
|
||||
}
|
||||
|
||||
static void SelectConstraints(MeshType &mesh,SmoothParam &SParam)
|
||||
{
|
||||
//clear all selected faces
|
||||
vcg::tri::UpdateFlags<MeshType>::FaceClear(mesh);
|
||||
|
||||
//add curvature hard constraints
|
||||
//ScalarType Ratio=mesh.bbox.Diag()*0.01;
|
||||
|
||||
if (SParam.curv_thr>0)
|
||||
AddCurvatureConstraints(mesh,SParam.curv_thr);///Ratio);
|
||||
|
||||
//add alignment to sharp features
|
||||
if (SParam.sharp_thr>0)
|
||||
AddSharpEdgesConstraints(mesh,SParam.sharp_thr);
|
||||
|
||||
//add border constraints
|
||||
if (SParam.align_borders)
|
||||
AddBorderConstraints(mesh);
|
||||
|
||||
//aff final constraints
|
||||
for (size_t i=0;i<SParam.AddConstr.size();i++)
|
||||
{
|
||||
int indexF=SParam.AddConstr[i].first;
|
||||
CoordType dir=SParam.AddConstr[i].second;
|
||||
mesh.face[indexF].PD1()=dir;
|
||||
mesh.face[indexF].PD2()=mesh.face[indexF].N()^dir;
|
||||
mesh.face[indexF].PD1().Normalize();
|
||||
mesh.face[indexF].PD2().Normalize();
|
||||
mesh.face[indexF].SetS();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
static void SmoothDirectionsIGL(MeshType &mesh,
|
||||
int Ndir,
|
||||
SmoothMethod SMethod=SMNPoly,
|
||||
bool HardAsS=true,
|
||||
ScalarType alphaSoft=0)
|
||||
{
|
||||
|
||||
assert((SMethod==SMNPoly)||(SMethod==SMMiq));
|
||||
|
||||
Eigen::VectorXi HardI; //hard constraints
|
||||
Eigen::MatrixXd HardD; //hard directions
|
||||
Eigen::VectorXi SoftI; //soft constraints
|
||||
Eigen::VectorXd SoftW; //weight of soft constraints
|
||||
Eigen::MatrixXd SoftD; //soft directions
|
||||
|
||||
if (HardAsS)
|
||||
CollectHardConstraints(mesh,HardI,HardD,SMethod,Ndir);
|
||||
|
||||
//collect soft constraints , miw only one that allows for soft constraints
|
||||
if ((alphaSoft>0)&&(SMethod==SMMiq))
|
||||
CollectSoftConstraints(mesh,SoftI,SoftD,SoftW);
|
||||
|
||||
//add some hard constraints if are not present
|
||||
int numC=3;
|
||||
if ((SoftI.rows()==0)&&(HardI.rows()==0))
|
||||
{
|
||||
printf("Add Forced Constraints \n");
|
||||
fflush(stdout);
|
||||
HardI=Eigen::MatrixXi(numC,1);
|
||||
|
||||
if ((Ndir==4)&&(SMethod==SMNPoly))
|
||||
HardD=Eigen::MatrixXd(numC,6);
|
||||
else
|
||||
HardD=Eigen::MatrixXd(numC,3);
|
||||
|
||||
for (int i=0;i<numC;i++)
|
||||
{
|
||||
CoordType Dir;
|
||||
int indexF;
|
||||
PickRandomDir(mesh,indexF,Dir);
|
||||
|
||||
HardI(i,0)=indexF;
|
||||
HardD(i,0)=Dir.X();
|
||||
HardD(i,1)=Dir.Y();
|
||||
HardD(i,2)=Dir.Z();
|
||||
|
||||
if ((Ndir==4)&&(SMethod==SMNPoly))
|
||||
{
|
||||
CoordType Dir1=mesh.face[indexF].N()^Dir;
|
||||
Dir1.Normalize();
|
||||
HardD(i,3)=Dir1.X();
|
||||
HardD(i,4)=Dir1.Y();
|
||||
HardD(i,5)=Dir1.Z();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//finally smooth
|
||||
if (SMethod==SMMiq)
|
||||
SmoothMIQ(mesh,HardI,HardD,SoftI,SoftD,SoftW,alphaSoft,Ndir);
|
||||
else
|
||||
{
|
||||
assert(SMethod==SMNPoly);
|
||||
SmoothNPoly(mesh,HardI,HardD,Ndir);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void SmoothDirections(MeshType &mesh,SmoothParam SParam)
|
||||
{
|
||||
|
||||
if ((SParam.SmoothM==SMMiq)||(SParam.SmoothM==SMNPoly))
|
||||
{
|
||||
// //initialize direction by curvature if needed
|
||||
if ((SParam.alpha_curv>0)||
|
||||
(SParam.sharp_thr>0)||
|
||||
(SParam.curv_thr>0))
|
||||
{
|
||||
InitByCurvature(mesh,SParam.curvRing);
|
||||
SelectConstraints(mesh,SParam);
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectConstraints(mesh,SParam);
|
||||
vcg::tri::CrossField<MeshType>::PropagateFromSelF(mesh);
|
||||
}
|
||||
SmoothDirectionsIGL(mesh,SParam.Ndir,SParam.SmoothM,true,SParam.alpha_curv);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout<<"ITERATIVE"<<std::endl;
|
||||
assert(SParam.SmoothM==SMIterative);
|
||||
InitByCurvature(mesh,SParam.curvRing);
|
||||
|
||||
if ((SParam.sharp_thr>0)||(SParam.curv_thr>0))
|
||||
SelectConstraints(mesh,SParam);
|
||||
|
||||
bool weightByAni=(SParam.alpha_curv>0);
|
||||
vcg::tri::CrossField<MeshType>::SmoothIterative(mesh,SParam.Ndir,(int)SParam.IteN,true,false,weightByAni);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // end namespace tri
|
||||
} // end namespace vcg
|
||||
#endif // SMOOTHER_FIELD_H
|
||||
Reference in new issue
Block a user