123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- // This file is part of libigl, a simple c++ geometry processing library.
- //
- // Copyright (C) 2016 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 "decimate.h"
- #include "collapse_edge.h"
- #include "edge_flaps.h"
- #include "is_edge_manifold.h"
- #include "remove_unreferenced.h"
- #include "slice_mask.h"
- #include "slice.h"
- #include "connect_boundary_to_infinity.h"
- #include "max_faces_stopping_condition.h"
- #include "shortest_edge_and_midpoint.h"
- IGL_INLINE bool igl::decimate(
- const Eigen::MatrixXd & V,
- const Eigen::MatrixXi & F,
- const size_t max_m,
- Eigen::MatrixXd & U,
- Eigen::MatrixXi & G,
- Eigen::VectorXi & J,
- Eigen::VectorXi & I)
- {
- // Original number of faces
- const int orig_m = F.rows();
- // Tracking number of faces
- int m = F.rows();
- typedef Eigen::MatrixXd DerivedV;
- typedef Eigen::MatrixXi DerivedF;
- DerivedV VO;
- DerivedF FO;
- igl::connect_boundary_to_infinity(V,F,VO,FO);
- // decimate will not work correctly on non-edge-manifold meshes. By extension
- // this includes meshes with non-manifold vertices on the boundary since these
- // will create a non-manifold edge when connected to infinity.
- if(!is_edge_manifold(FO))
- {
- return false;
- }
- bool ret = decimate(
- VO,
- FO,
- shortest_edge_and_midpoint,
- max_faces_stopping_condition(m,orig_m,max_m),
- U,
- G,
- J,
- I);
- const Eigen::Array<bool,Eigen::Dynamic,1> keep = (J.array()<orig_m);
- igl::slice_mask(Eigen::MatrixXi(G),keep,1,G);
- igl::slice_mask(Eigen::VectorXi(J),keep,1,J);
- Eigen::VectorXi _1,I2;
- igl::remove_unreferenced(Eigen::MatrixXd(U),Eigen::MatrixXi(G),U,G,_1,I2);
- igl::slice(Eigen::VectorXi(I),I2,1,I);
- return ret;
- }
- IGL_INLINE bool igl::decimate(
- const Eigen::MatrixXd & V,
- const Eigen::MatrixXi & F,
- const size_t max_m,
- Eigen::MatrixXd & U,
- Eigen::MatrixXi & G,
- Eigen::VectorXi & J)
- {
- Eigen::VectorXi I;
- return igl::decimate(V,F,max_m,U,G,J,I);
- }
- IGL_INLINE bool igl::decimate(
- const Eigen::MatrixXd & OV,
- const Eigen::MatrixXi & OF,
- const std::function<void(
- const int,
- const Eigen::MatrixXd &,
- const Eigen::MatrixXi &,
- const Eigen::MatrixXi &,
- const Eigen::VectorXi &,
- const Eigen::MatrixXi &,
- const Eigen::MatrixXi &,
- double &,
- Eigen::RowVectorXd &)> & cost_and_placement,
- const std::function<bool(
- const Eigen::MatrixXd &,
- const Eigen::MatrixXi &,
- const Eigen::MatrixXi &,
- const Eigen::VectorXi &,
- const Eigen::MatrixXi &,
- const Eigen::MatrixXi &,
- const std::set<std::pair<double,int> > &,
- const std::vector<std::set<std::pair<double,int> >::iterator > &,
- const Eigen::MatrixXd &,
- const int,
- const int,
- const int,
- const int,
- const int)> & stopping_condition,
- Eigen::MatrixXd & U,
- Eigen::MatrixXi & G,
- Eigen::VectorXi & J,
- Eigen::VectorXi & I
- )
- {
- const auto always_try = [](
- const Eigen::MatrixXd & ,/*V*/
- const Eigen::MatrixXi & ,/*F*/
- const Eigen::MatrixXi & ,/*E*/
- const Eigen::VectorXi & ,/*EMAP*/
- const Eigen::MatrixXi & ,/*EF*/
- const Eigen::MatrixXi & ,/*EI*/
- const std::set<std::pair<double,int> > & ,/*Q*/
- const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
- const Eigen::MatrixXd & ,/*C*/
- const int /*e*/
- ) -> bool { return true;};
- const auto never_care = [](
- const Eigen::MatrixXd & , /*V*/
- const Eigen::MatrixXi & , /*F*/
- const Eigen::MatrixXi & , /*E*/
- const Eigen::VectorXi & ,/*EMAP*/
- const Eigen::MatrixXi & , /*EF*/
- const Eigen::MatrixXi & , /*EI*/
- const std::set<std::pair<double,int> > & , /*Q*/
- const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
- const Eigen::MatrixXd & , /*C*/
- const int , /*e*/
- const int , /*e1*/
- const int , /*e2*/
- const int , /*f1*/
- const int , /*f2*/
- const bool /*collapsed*/
- )-> void { };
- return igl::decimate(
- OV,OF,cost_and_placement,stopping_condition,always_try,never_care,U,G,J,I);
- }
- IGL_INLINE bool igl::decimate(
- const Eigen::MatrixXd & OV,
- const Eigen::MatrixXi & OF,
- const std::function<void(
- const int,
- const Eigen::MatrixXd &,
- const Eigen::MatrixXi &,
- const Eigen::MatrixXi &,
- const Eigen::VectorXi &,
- const Eigen::MatrixXi &,
- const Eigen::MatrixXi &,
- double &,
- Eigen::RowVectorXd &)> & cost_and_placement,
- const std::function<bool(
- const Eigen::MatrixXd &,
- const Eigen::MatrixXi &,
- const Eigen::MatrixXi &,
- const Eigen::VectorXi &,
- const Eigen::MatrixXi &,
- const Eigen::MatrixXi &,
- const std::set<std::pair<double,int> > &,
- const std::vector<std::set<std::pair<double,int> >::iterator > &,
- const Eigen::MatrixXd &,
- const int,
- const int,
- const int,
- const int,
- const int)> & stopping_condition,
- const std::function<bool(
- const Eigen::MatrixXd & ,/*V*/
- const Eigen::MatrixXi & ,/*F*/
- const Eigen::MatrixXi & ,/*E*/
- const Eigen::VectorXi & ,/*EMAP*/
- const Eigen::MatrixXi & ,/*EF*/
- const Eigen::MatrixXi & ,/*EI*/
- const std::set<std::pair<double,int> > & ,/*Q*/
- const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
- const Eigen::MatrixXd & ,/*C*/
- const int /*e*/
- )> & pre_collapse,
- const std::function<void(
- const Eigen::MatrixXd & , /*V*/
- const Eigen::MatrixXi & , /*F*/
- const Eigen::MatrixXi & , /*E*/
- const Eigen::VectorXi & ,/*EMAP*/
- const Eigen::MatrixXi & , /*EF*/
- const Eigen::MatrixXi & , /*EI*/
- const std::set<std::pair<double,int> > & , /*Q*/
- const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
- const Eigen::MatrixXd & , /*C*/
- const int , /*e*/
- const int , /*e1*/
- const int , /*e2*/
- const int , /*f1*/
- const int , /*f2*/
- const bool /*collapsed*/
- )> & post_collapse,
- Eigen::MatrixXd & U,
- Eigen::MatrixXi & G,
- Eigen::VectorXi & J,
- Eigen::VectorXi & I
- )
- {
- using namespace Eigen;
- using namespace std;
- VectorXi EMAP;
- MatrixXi E,EF,EI;
- edge_flaps(OF,E,EMAP,EF,EI);
- return igl::decimate(
- OV,OF,
- cost_and_placement,stopping_condition,pre_collapse,post_collapse,
- E,EMAP,EF,EI,
- U,G,J,I);
- }
- IGL_INLINE bool igl::decimate(
- const Eigen::MatrixXd & OV,
- const Eigen::MatrixXi & OF,
- const std::function<void(
- const int,
- const Eigen::MatrixXd &,
- const Eigen::MatrixXi &,
- const Eigen::MatrixXi &,
- const Eigen::VectorXi &,
- const Eigen::MatrixXi &,
- const Eigen::MatrixXi &,
- double &,
- Eigen::RowVectorXd &)> & cost_and_placement,
- const std::function<bool(
- const Eigen::MatrixXd &,
- const Eigen::MatrixXi &,
- const Eigen::MatrixXi &,
- const Eigen::VectorXi &,
- const Eigen::MatrixXi &,
- const Eigen::MatrixXi &,
- const std::set<std::pair<double,int> > &,
- const std::vector<std::set<std::pair<double,int> >::iterator > &,
- const Eigen::MatrixXd &,
- const int,
- const int,
- const int,
- const int,
- const int)> & stopping_condition,
- const std::function<bool(
- const Eigen::MatrixXd & ,/*V*/
- const Eigen::MatrixXi & ,/*F*/
- const Eigen::MatrixXi & ,/*E*/
- const Eigen::VectorXi & ,/*EMAP*/
- const Eigen::MatrixXi & ,/*EF*/
- const Eigen::MatrixXi & ,/*EI*/
- const std::set<std::pair<double,int> > & ,/*Q*/
- const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
- const Eigen::MatrixXd & ,/*C*/
- const int /*e*/
- )> & pre_collapse,
- const std::function<void(
- const Eigen::MatrixXd & , /*V*/
- const Eigen::MatrixXi & , /*F*/
- const Eigen::MatrixXi & , /*E*/
- const Eigen::VectorXi & ,/*EMAP*/
- const Eigen::MatrixXi & , /*EF*/
- const Eigen::MatrixXi & , /*EI*/
- const std::set<std::pair<double,int> > & , /*Q*/
- const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
- const Eigen::MatrixXd & , /*C*/
- const int , /*e*/
- const int , /*e1*/
- const int , /*e2*/
- const int , /*f1*/
- const int , /*f2*/
- const bool /*collapsed*/
- )> & post_collapse,
- const Eigen::MatrixXi & OE,
- const Eigen::VectorXi & OEMAP,
- const Eigen::MatrixXi & OEF,
- const Eigen::MatrixXi & OEI,
- Eigen::MatrixXd & U,
- Eigen::MatrixXi & G,
- Eigen::VectorXi & J,
- Eigen::VectorXi & I
- )
- {
- // Decimate 1
- using namespace Eigen;
- using namespace std;
- // Working copies
- Eigen::MatrixXd V = OV;
- Eigen::MatrixXi F = OF;
- Eigen::MatrixXi E = OE;
- Eigen::VectorXi EMAP = OEMAP;
- Eigen::MatrixXi EF = OEF;
- Eigen::MatrixXi EI = OEI;
- typedef std::set<std::pair<double,int> > PriorityQueue;
- PriorityQueue Q;
- std::vector<PriorityQueue::iterator > Qit;
- Qit.resize(E.rows());
- // If an edge were collapsed, we'd collapse it to these points:
- MatrixXd C(E.rows(),V.cols());
- for(int e = 0;e<E.rows();e++)
- {
- double cost = e;
- RowVectorXd p(1,3);
- cost_and_placement(e,V,F,E,EMAP,EF,EI,cost,p);
- C.row(e) = p;
- Qit[e] = Q.insert(std::pair<double,int>(cost,e)).first;
- }
- int prev_e = -1;
- bool clean_finish = false;
- while(true)
- {
- if(Q.empty())
- {
- break;
- }
- if(Q.begin()->first == std::numeric_limits<double>::infinity())
- {
- // min cost edge is infinite cost
- break;
- }
- int e,e1,e2,f1,f2;
- if(collapse_edge(
- cost_and_placement, pre_collapse, post_collapse,
- V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2))
- {
- if(stopping_condition(V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2))
- {
- clean_finish = true;
- break;
- }
- }else
- {
- if(prev_e == e)
- {
- assert(false && "Edge collapse no progress... bad stopping condition?");
- break;
- }
- // Edge was not collapsed... must have been invalid. collapse_edge should
- // have updated its cost to inf... continue
- }
- prev_e = e;
- }
- // remove all IGL_COLLAPSE_EDGE_NULL faces
- MatrixXi F2(F.rows(),3);
- J.resize(F.rows());
- int m = 0;
- for(int f = 0;f<F.rows();f++)
- {
- if(
- F(f,0) != IGL_COLLAPSE_EDGE_NULL ||
- F(f,1) != IGL_COLLAPSE_EDGE_NULL ||
- F(f,2) != IGL_COLLAPSE_EDGE_NULL)
- {
- F2.row(m) = F.row(f);
- J(m) = f;
- m++;
- }
- }
- F2.conservativeResize(m,F2.cols());
- J.conservativeResize(m);
- VectorXi _1;
- remove_unreferenced(V,F2,U,G,_1,I);
- return clean_finish;
- }
|