123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- // This file is part of libigl, a simple c++ geometry processing library.
- //
- // Copyright (C) 2015 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 "progressive_hulls_cost_and_placement.h"
- #include "quadprog.h"
- #include "../unique.h"
- #include "../circulation.h"
- #include <cassert>
- #include <vector>
- #include <limits>
- IGL_INLINE void igl::copyleft::progressive_hulls_cost_and_placement(
- const int e,
- const Eigen::MatrixXd & V,
- const Eigen::MatrixXi & F,
- const Eigen::MatrixXi & E,
- const Eigen::VectorXi & EMAP,
- const Eigen::MatrixXi & EF,
- const Eigen::MatrixXi & EI,
- double & cost,
- Eigen::RowVectorXd & p)
- {
- using namespace Eigen;
- using namespace std;
- // Controls the amount of quadratic energy to add (too small will introduce
- // instabilities and flaps)
- const double w = 0.1;
- assert(V.cols() == 3 && "V.cols() should be 3");
- // Gather list of unique face neighbors
- vector<int> Nall = circulation(e, true,F,E,EMAP,EF,EI);
- vector<int> Nother= circulation(e,false,F,E,EMAP,EF,EI);
- Nall.insert(Nall.end(),Nother.begin(),Nother.end());
- vector<int> N;
- igl::unique(Nall,N);
- // Gather:
- // A #N by 3 normals scaled by area,
- // D #N determinants of matrix formed by points as columns
- // B #N point on plane dot normal
- MatrixXd A(N.size(),3);
- VectorXd D(N.size());
- VectorXd B(N.size());
- //cout<<"N=[";
- for(int i = 0;i<N.size();i++)
- {
- const int f = N[i];
- //cout<<(f+1)<<" ";
- const RowVector3d & v01 = V.row(F(f,1))-V.row(F(f,0));
- const RowVector3d & v20 = V.row(F(f,2))-V.row(F(f,0));
- A.row(i) = v01.cross(v20);
- B(i) = V.row(F(f,0)).dot(A.row(i));
- D(i) =
- (Matrix3d()<< V.row(F(f,0)), V.row(F(f,1)), V.row(F(f,2)))
- .finished().determinant();
- }
- //cout<<"];"<<endl;
- // linear objective
- Vector3d f = A.colwise().sum().transpose();
- VectorXd x;
- //bool success = linprog(f,-A,-B,MatrixXd(0,A.cols()),VectorXd(0,1),x);
- //VectorXd _;
- //bool success = mosek_linprog(f,A.sparseView(),B,_,_,_,env,x);
- //if(success)
- //{
- // cost = (1./6.)*(x.dot(f) - D.sum());
- //}
- bool success = false;
- {
- RowVectorXd mid = 0.5*(V.row(E(e,0))+V.row(E(e,1)));
- MatrixXd G = w*Matrix3d::Identity(3,3);
- VectorXd g0 = (1.-w)*f - w*mid.transpose();
- const int n = A.cols();
- success = quadprog(
- G,g0,
- MatrixXd(n,0),VectorXd(0,1),
- A.transpose(),-B,x);
- cost = (1.-w)*(1./6.)*(x.dot(f) - D.sum()) +
- w*(x.transpose()-mid).squaredNorm() +
- w*(V.row(E(e,0))-V.row(E(e,1))).norm();
- }
- // A x >= B
- // A x - B >=0
- // This is annoyingly necessary. Seems the solver is letting some garbage
- // slip by.
- success = success && ((A*x-B).minCoeff()>-1e-10);
- if(success)
- {
- p = x.transpose();
- //assert(cost>=0 && "Cost should be positive");
- }else
- {
- cost = std::numeric_limits<double>::infinity();
- //VectorXi NM;
- //igl::list_to_matrix(N,NM);
- //cout<<matlab_format((NM.array()+1).eval(),"N")<<endl;
- //cout<<matlab_format(f,"f")<<endl;
- //cout<<matlab_format(A,"A")<<endl;
- //cout<<matlab_format(B,"B")<<endl;
- //exit(-1);
- p = RowVectorXd::Constant(1,3,std::nan("inf-cost"));
- }
- }
|