117 lines
3.0 KiB
C++
117 lines
3.0 KiB
C++
// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#include "bone_heat.h"
|
|
#include "EmbreeIntersector.h"
|
|
#include "bone_visible.h"
|
|
#include "../project_to_line_segment.h"
|
|
#include "../cotmatrix.h"
|
|
#include "../massmatrix.h"
|
|
#include "../mat_min.h"
|
|
#include <Eigen/Sparse>
|
|
|
|
bool igl::embree::bone_heat(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const Eigen::MatrixXd & C,
|
|
const Eigen::VectorXi & P,
|
|
const Eigen::MatrixXi & BE,
|
|
const Eigen::MatrixXi & CE,
|
|
Eigen::MatrixXd & W)
|
|
{
|
|
using namespace std;
|
|
using namespace Eigen;
|
|
assert(CE.rows() == 0 && "Cage edges not supported.");
|
|
assert(C.cols() == V.cols() && "V and C should have same #cols");
|
|
assert(BE.cols() == 2 && "BE should have #cols=2");
|
|
assert(F.cols() == 3 && "F should contain triangles.");
|
|
assert(V.cols() == 3 && "V should contain 3D positions.");
|
|
|
|
const int n = V.rows();
|
|
const int np = P.rows();
|
|
const int nb = BE.rows();
|
|
const int m = np + nb;
|
|
|
|
// "double sided lighting"
|
|
MatrixXi FF;
|
|
FF.resize(F.rows()*2,F.cols());
|
|
FF << F, F.rowwise().reverse();
|
|
// Initialize intersector
|
|
EmbreeIntersector ei;
|
|
ei.init(V.cast<float>(),F.cast<int>());
|
|
|
|
typedef Matrix<bool,Dynamic,1> VectorXb;
|
|
typedef Matrix<bool,Dynamic,Dynamic> MatrixXb;
|
|
MatrixXb vis_mask(n,m);
|
|
// Distances
|
|
MatrixXd D(n,m);
|
|
// loop over points
|
|
for(int j = 0;j<np;j++)
|
|
{
|
|
const Vector3d p = C.row(P(j));
|
|
D.col(j) = (V.rowwise()-p.transpose()).rowwise().norm();
|
|
VectorXb vj;
|
|
bone_visible(V,F,ei,p,p,vj);
|
|
vis_mask.col(j) = vj;
|
|
}
|
|
|
|
// loop over bones
|
|
for(int j = 0;j<nb;j++)
|
|
{
|
|
const Vector3d s = C.row(BE(j,0));
|
|
const Vector3d d = C.row(BE(j,1));
|
|
VectorXd t,sqrD;
|
|
project_to_line_segment(V,s,d,t,sqrD);
|
|
D.col(np+j) = sqrD.array().sqrt();
|
|
VectorXb vj;
|
|
bone_visible(V,F,ei,s,d,vj);
|
|
vis_mask.col(np+j) = vj;
|
|
}
|
|
|
|
if(CE.rows() > 0)
|
|
{
|
|
cerr<<"Error: Cage edges are not supported. Ignored."<<endl;
|
|
}
|
|
|
|
MatrixXd PP = MatrixXd::Zero(n,m);
|
|
VectorXd min_D;
|
|
VectorXd Hdiag = VectorXd::Zero(n);
|
|
VectorXi J;
|
|
mat_min(D,2,min_D,J);
|
|
for(int i = 0;i<n;i++)
|
|
{
|
|
PP(i,J(i)) = 1;
|
|
if(vis_mask(i,J(i)))
|
|
{
|
|
double hii = pow(min_D(i),-2.);
|
|
Hdiag(i) = (hii>1e10?1e10:hii);
|
|
}
|
|
}
|
|
SparseMatrix<double> Q,L,M;
|
|
cotmatrix(V,F,L);
|
|
massmatrix(V,F,MASSMATRIX_TYPE_DEFAULT,M);
|
|
const auto & H = Hdiag.asDiagonal();
|
|
Q = (-L+M*H);
|
|
SimplicialLLT <SparseMatrix<double > > llt;
|
|
llt.compute(Q);
|
|
switch(llt.info())
|
|
{
|
|
case Eigen::Success:
|
|
break;
|
|
case Eigen::NumericalIssue:
|
|
cerr<<"Error: Numerical issue."<<endl;
|
|
return false;
|
|
default:
|
|
cerr<<"Error: Other."<<endl;
|
|
return false;
|
|
}
|
|
|
|
const auto & rhs = M*H*PP;
|
|
W = llt.solve(rhs);
|
|
return true;
|
|
}
|