|
@@ -8,6 +8,7 @@
|
|
|
#include "collapse_edge.h"
|
|
#include "collapse_edge.h"
|
|
|
#include "circulation.h"
|
|
#include "circulation.h"
|
|
|
#include "edge_collapse_is_valid.h"
|
|
#include "edge_collapse_is_valid.h"
|
|
|
|
|
+#include "always_try_never_care.h"
|
|
|
#include <vector>
|
|
#include <vector>
|
|
|
|
|
|
|
|
IGL_INLINE bool igl::collapse_edge(
|
|
IGL_INLINE bool igl::collapse_edge(
|
|
@@ -19,6 +20,32 @@ IGL_INLINE bool igl::collapse_edge(
|
|
|
Eigen::VectorXi & EMAP,
|
|
Eigen::VectorXi & EMAP,
|
|
|
Eigen::MatrixXi & EF,
|
|
Eigen::MatrixXi & EF,
|
|
|
Eigen::MatrixXi & EI,
|
|
Eigen::MatrixXi & EI,
|
|
|
|
|
+ int & e1,
|
|
|
|
|
+ int & e2,
|
|
|
|
|
+ int & f1,
|
|
|
|
|
+ int & f2)
|
|
|
|
|
+{
|
|
|
|
|
+ std::vector<int> /*Nse,*/Nsf,Nsv;
|
|
|
|
|
+ circulation(e, true,F,EMAP,EF,EI,/*Nse,*/Nsv,Nsf);
|
|
|
|
|
+ std::vector<int> /*Nde,*/Ndf,Ndv;
|
|
|
|
|
+ circulation(e, false,F,EMAP,EF,EI,/*Nde,*/Ndv,Ndf);
|
|
|
|
|
+ return collapse_edge(
|
|
|
|
|
+ e,p,Nsv,Nsf,Ndv,Ndf,V,F,E,EMAP,EF,EI,e1,e2,f1,f2);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+IGL_INLINE bool igl::collapse_edge(
|
|
|
|
|
+ const int e,
|
|
|
|
|
+ const Eigen::RowVectorXd & p,
|
|
|
|
|
+ /*const*/ std::vector<int> & Nsv,
|
|
|
|
|
+ const std::vector<int> & Nsf,
|
|
|
|
|
+ /*const*/ std::vector<int> & Ndv,
|
|
|
|
|
+ const std::vector<int> & Ndf,
|
|
|
|
|
+ Eigen::MatrixXd & V,
|
|
|
|
|
+ Eigen::MatrixXi & F,
|
|
|
|
|
+ Eigen::MatrixXi & E,
|
|
|
|
|
+ Eigen::VectorXi & EMAP,
|
|
|
|
|
+ Eigen::MatrixXi & EF,
|
|
|
|
|
+ Eigen::MatrixXi & EI,
|
|
|
int & a_e1,
|
|
int & a_e1,
|
|
|
int & a_e2,
|
|
int & a_e2,
|
|
|
int & a_f1,
|
|
int & a_f1,
|
|
@@ -34,17 +61,19 @@ IGL_INLINE bool igl::collapse_edge(
|
|
|
const int s = eflip?E(e,1):E(e,0);
|
|
const int s = eflip?E(e,1):E(e,0);
|
|
|
const int d = eflip?E(e,0):E(e,1);
|
|
const int d = eflip?E(e,0):E(e,1);
|
|
|
|
|
|
|
|
- if(!edge_collapse_is_valid(e,F,E,EMAP,EF,EI))
|
|
|
|
|
|
|
+ if(!edge_collapse_is_valid(Nsv,Ndv))
|
|
|
{
|
|
{
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // OVERLOAD: caller may have just computed this
|
|
|
|
|
+ //
|
|
|
// Important to grab neighbors of d before monkeying with edges
|
|
// Important to grab neighbors of d before monkeying with edges
|
|
|
- const std::vector<int> nV2Fd = circulation(e,!eflip,EMAP,EF,EI);
|
|
|
|
|
|
|
+ const std::vector<int> & nV2Fd = (!eflip ? Nsf : Ndf);
|
|
|
|
|
|
|
|
// The following implementation strongly relies on s<d
|
|
// The following implementation strongly relies on s<d
|
|
|
assert(s<d && "s should be less than d");
|
|
assert(s<d && "s should be less than d");
|
|
|
- // move source and destination to midpoint
|
|
|
|
|
|
|
+ // move source and destination to placement
|
|
|
V.row(s) = p;
|
|
V.row(s) = p;
|
|
|
V.row(d) = p;
|
|
V.row(d) = p;
|
|
|
|
|
|
|
@@ -112,31 +141,40 @@ IGL_INLINE bool igl::collapse_edge(
|
|
|
// make sense.
|
|
// make sense.
|
|
|
//
|
|
//
|
|
|
// Could actually skip first and last, since those are always the two
|
|
// Could actually skip first and last, since those are always the two
|
|
|
- // collpased faces.
|
|
|
|
|
- for(auto f : nV2Fd)
|
|
|
|
|
|
|
+ // collpased faces. Nah, this is handled by (F(f,v) == d)
|
|
|
|
|
+ //
|
|
|
|
|
+ // Don't attempt to use Nde,Nse here because EMAP has changed
|
|
|
{
|
|
{
|
|
|
- for(int v = 0;v<3;v++)
|
|
|
|
|
|
|
+ int p1 = -1;
|
|
|
|
|
+ for(auto f : nV2Fd)
|
|
|
{
|
|
{
|
|
|
- if(F(f,v) == d)
|
|
|
|
|
|
|
+ for(int v = 0;v<3;v++)
|
|
|
{
|
|
{
|
|
|
- const int flip1 = (EF(EMAP(f+m*((v+1)%3)),0)==f)?1:0;
|
|
|
|
|
- const int flip2 = (EF(EMAP(f+m*((v+2)%3)),0)==f)?0:1;
|
|
|
|
|
- assert(
|
|
|
|
|
- E(EMAP(f+m*((v+1)%3)),flip1) == d ||
|
|
|
|
|
- E(EMAP(f+m*((v+1)%3)),flip1) == s);
|
|
|
|
|
- E(EMAP(f+m*((v+1)%3)),flip1) = s;
|
|
|
|
|
- assert(
|
|
|
|
|
- E(EMAP(f+m*((v+2)%3)),flip2) == d ||
|
|
|
|
|
- E(EMAP(f+m*((v+2)%3)),flip2) == s);
|
|
|
|
|
- E(EMAP(f+m*((v+2)%3)),flip2) = s;
|
|
|
|
|
- F(f,v) = s;
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ if(F(f,v) == d)
|
|
|
|
|
+ {
|
|
|
|
|
+ const int e1 = EMAP(f+m*((v+1)%3));
|
|
|
|
|
+ const int flip1 = (EF(e1,0)==f)?1:0;
|
|
|
|
|
+ assert( E(e1,flip1) == d || E(e1,flip1) == s);
|
|
|
|
|
+ E(e1,flip1) = s;
|
|
|
|
|
+ const int e2 = EMAP(f+m*((v+2)%3));
|
|
|
|
|
+ // Skip if we just handled this edge (claim: this will be all except
|
|
|
|
|
+ // for the first non-trivial face)
|
|
|
|
|
+ if(e2 != p1)
|
|
|
|
|
+ {
|
|
|
|
|
+ const int flip2 = (EF(e2,0)==f)?0:1;
|
|
|
|
|
+ assert( E(e2,flip2) == d || E(e2,flip2) == s);
|
|
|
|
|
+ E(e2,flip2) = s;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ F(f,v) = s;
|
|
|
|
|
+ p1 = e1;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
// Finally, "remove" this edge and its information
|
|
// Finally, "remove" this edge and its information
|
|
|
kill_edge(e);
|
|
kill_edge(e);
|
|
|
-
|
|
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -155,168 +193,61 @@ IGL_INLINE bool igl::collapse_edge(
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
IGL_INLINE bool igl::collapse_edge(
|
|
IGL_INLINE bool igl::collapse_edge(
|
|
|
- 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 decimate_cost_and_placement_func & cost_and_placement,
|
|
|
Eigen::MatrixXd & V,
|
|
Eigen::MatrixXd & V,
|
|
|
Eigen::MatrixXi & F,
|
|
Eigen::MatrixXi & F,
|
|
|
Eigen::MatrixXi & E,
|
|
Eigen::MatrixXi & E,
|
|
|
Eigen::VectorXi & EMAP,
|
|
Eigen::VectorXi & EMAP,
|
|
|
Eigen::MatrixXi & EF,
|
|
Eigen::MatrixXi & EF,
|
|
|
Eigen::MatrixXi & EI,
|
|
Eigen::MatrixXi & EI,
|
|
|
- std::set<std::pair<double,int> > & Q,
|
|
|
|
|
- std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
|
|
|
|
|
|
|
+ igl::min_heap< std::tuple<double,int,int> > & Q,
|
|
|
|
|
+ Eigen::VectorXi & EQ,
|
|
|
Eigen::MatrixXd & C)
|
|
Eigen::MatrixXd & C)
|
|
|
{
|
|
{
|
|
|
int e,e1,e2,f1,f2;
|
|
int e,e1,e2,f1,f2;
|
|
|
- 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 { };
|
|
|
|
|
|
|
+ decimate_pre_collapse_func always_try;
|
|
|
|
|
+ decimate_post_collapse_func never_care;
|
|
|
|
|
+ always_try_never_care(always_try,never_care);
|
|
|
return
|
|
return
|
|
|
collapse_edge(
|
|
collapse_edge(
|
|
|
cost_and_placement,always_try,never_care,
|
|
cost_and_placement,always_try,never_care,
|
|
|
- V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2);
|
|
|
|
|
|
|
+ V,F,E,EMAP,EF,EI,Q,EQ,C,e,e1,e2,f1,f2);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
IGL_INLINE bool igl::collapse_edge(
|
|
IGL_INLINE bool igl::collapse_edge(
|
|
|
- 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 & ,/*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 decimate_cost_and_placement_func & cost_and_placement,
|
|
|
|
|
+ const decimate_pre_collapse_func & pre_collapse,
|
|
|
|
|
+ const decimate_post_collapse_func & post_collapse,
|
|
|
Eigen::MatrixXd & V,
|
|
Eigen::MatrixXd & V,
|
|
|
Eigen::MatrixXi & F,
|
|
Eigen::MatrixXi & F,
|
|
|
Eigen::MatrixXi & E,
|
|
Eigen::MatrixXi & E,
|
|
|
Eigen::VectorXi & EMAP,
|
|
Eigen::VectorXi & EMAP,
|
|
|
Eigen::MatrixXi & EF,
|
|
Eigen::MatrixXi & EF,
|
|
|
Eigen::MatrixXi & EI,
|
|
Eigen::MatrixXi & EI,
|
|
|
- std::set<std::pair<double,int> > & Q,
|
|
|
|
|
- std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
|
|
|
|
|
|
|
+ igl::min_heap< std::tuple<double,int,int> > & Q,
|
|
|
|
|
+ Eigen::VectorXi & EQ,
|
|
|
Eigen::MatrixXd & C)
|
|
Eigen::MatrixXd & C)
|
|
|
{
|
|
{
|
|
|
int e,e1,e2,f1,f2;
|
|
int e,e1,e2,f1,f2;
|
|
|
return
|
|
return
|
|
|
collapse_edge(
|
|
collapse_edge(
|
|
|
cost_and_placement,pre_collapse,post_collapse,
|
|
cost_and_placement,pre_collapse,post_collapse,
|
|
|
- V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2);
|
|
|
|
|
|
|
+ V,F,E,EMAP,EF,EI,Q,EQ,C,e,e1,e2,f1,f2);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
IGL_INLINE bool igl::collapse_edge(
|
|
IGL_INLINE bool igl::collapse_edge(
|
|
|
- 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 & ,/*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 decimate_cost_and_placement_func & cost_and_placement,
|
|
|
|
|
+ const decimate_pre_collapse_func & pre_collapse,
|
|
|
|
|
+ const decimate_post_collapse_func & post_collapse,
|
|
|
Eigen::MatrixXd & V,
|
|
Eigen::MatrixXd & V,
|
|
|
Eigen::MatrixXi & F,
|
|
Eigen::MatrixXi & F,
|
|
|
Eigen::MatrixXi & E,
|
|
Eigen::MatrixXi & E,
|
|
|
Eigen::VectorXi & EMAP,
|
|
Eigen::VectorXi & EMAP,
|
|
|
Eigen::MatrixXi & EF,
|
|
Eigen::MatrixXi & EF,
|
|
|
Eigen::MatrixXi & EI,
|
|
Eigen::MatrixXi & EI,
|
|
|
- std::set<std::pair<double,int> > & Q,
|
|
|
|
|
- std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
|
|
|
|
|
|
|
+ igl::min_heap< std::tuple<double,int,int> > & Q,
|
|
|
|
|
+ Eigen::VectorXi & EQ,
|
|
|
Eigen::MatrixXd & C,
|
|
Eigen::MatrixXd & C,
|
|
|
int & e,
|
|
int & e,
|
|
|
int & e1,
|
|
int & e1,
|
|
@@ -325,43 +256,80 @@ IGL_INLINE bool igl::collapse_edge(
|
|
|
int & f2)
|
|
int & f2)
|
|
|
{
|
|
{
|
|
|
using namespace Eigen;
|
|
using namespace Eigen;
|
|
|
- if(Q.empty())
|
|
|
|
|
|
|
+ using namespace igl;
|
|
|
|
|
+ std::tuple<double,int,int> p;
|
|
|
|
|
+ while(true)
|
|
|
{
|
|
{
|
|
|
- // no edges to collapse
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
- std::pair<double,int> p = *(Q.begin());
|
|
|
|
|
- if(p.first == std::numeric_limits<double>::infinity())
|
|
|
|
|
- {
|
|
|
|
|
- // min cost edge is infinite cost
|
|
|
|
|
- return false;
|
|
|
|
|
|
|
+ // Check if Q is empty
|
|
|
|
|
+ if(Q.empty())
|
|
|
|
|
+ {
|
|
|
|
|
+ // no edges to collapse
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ // pop from Q
|
|
|
|
|
+ p = Q.top();
|
|
|
|
|
+ if(std::get<0>(p) == std::numeric_limits<double>::infinity())
|
|
|
|
|
+ {
|
|
|
|
|
+ // min cost edge is infinite cost
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ Q.pop();
|
|
|
|
|
+ e = std::get<1>(p);
|
|
|
|
|
+ // Check if matches timestamp
|
|
|
|
|
+ if(std::get<2>(p) == EQ(e))
|
|
|
|
|
+ {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ // must be stale or dead.
|
|
|
|
|
+ assert(std::get<2>(p) < EQ(e) || EQ(e) == -1);
|
|
|
|
|
+ // try again.
|
|
|
}
|
|
}
|
|
|
- Q.erase(Q.begin());
|
|
|
|
|
- e = p.second;
|
|
|
|
|
- Qit[e] = Q.end();
|
|
|
|
|
- std::vector<int> N = circulation(e, true,EMAP,EF,EI);
|
|
|
|
|
- std::vector<int> Nd = circulation(e,false,EMAP,EF,EI);
|
|
|
|
|
- N.insert(N.begin(),Nd.begin(),Nd.end());
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // Why is this computed up here?
|
|
|
|
|
+ // If we just need original face neighbors of edge, could we gather that more
|
|
|
|
|
+ // directly than gathering face neighbors of each vertex?
|
|
|
|
|
+ std::vector<int> /*Nse,*/Nsf,Nsv;
|
|
|
|
|
+ circulation(e, true,F,EMAP,EF,EI,/*Nse,*/Nsv,Nsf);
|
|
|
|
|
+ std::vector<int> /*Nde,*/Ndf,Ndv;
|
|
|
|
|
+ circulation(e, false,F,EMAP,EF,EI,/*Nde,*/Ndv,Ndf);
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
bool collapsed = true;
|
|
bool collapsed = true;
|
|
|
- if(pre_collapse(V,F,E,EMAP,EF,EI,Q,Qit,C,e))
|
|
|
|
|
|
|
+ if(pre_collapse(V,F,E,EMAP,EF,EI,Q,EQ,C,e))
|
|
|
{
|
|
{
|
|
|
- collapsed = collapse_edge(e,C.row(e),V,F,E,EMAP,EF,EI,e1,e2,f1,f2);
|
|
|
|
|
|
|
+ collapsed = collapse_edge(
|
|
|
|
|
+ e,C.row(e),
|
|
|
|
|
+ Nsv,Nsf,Ndv,Ndf,
|
|
|
|
|
+ V,F,E,EMAP,EF,EI,e1,e2,f1,f2);
|
|
|
}else
|
|
}else
|
|
|
{
|
|
{
|
|
|
// Aborted by pre collapse callback
|
|
// Aborted by pre collapse callback
|
|
|
collapsed = false;
|
|
collapsed = false;
|
|
|
}
|
|
}
|
|
|
- post_collapse(V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2,collapsed);
|
|
|
|
|
|
|
+ post_collapse(V,F,E,EMAP,EF,EI,Q,EQ,C,e,e1,e2,f1,f2,collapsed);
|
|
|
if(collapsed)
|
|
if(collapsed)
|
|
|
{
|
|
{
|
|
|
- // Erase the two, other collapsed edges
|
|
|
|
|
- Q.erase(Qit[e1]);
|
|
|
|
|
- Qit[e1] = Q.end();
|
|
|
|
|
- Q.erase(Qit[e2]);
|
|
|
|
|
- Qit[e2] = Q.end();
|
|
|
|
|
|
|
+ // Erase the two, other collapsed edges by marking their timestamps as -1
|
|
|
|
|
+ EQ(e1) = -1;
|
|
|
|
|
+ EQ(e2) = -1;
|
|
|
|
|
+ // TODO: visits edges multiple times, ~150% more updates than should
|
|
|
|
|
+ //
|
|
|
// update local neighbors
|
|
// update local neighbors
|
|
|
// loop over original face neighbors
|
|
// loop over original face neighbors
|
|
|
- for(auto n : N)
|
|
|
|
|
|
|
+ //
|
|
|
|
|
+ // Can't use previous computed Nse and Nde because those refer to EMAP
|
|
|
|
|
+ // before it was changed...
|
|
|
|
|
+ std::vector<int> Nf;
|
|
|
|
|
+ Nf.reserve( Nsf.size() + Ndf.size() ); // preallocate memory
|
|
|
|
|
+ Nf.insert( Nf.end(), Nsf.begin(), Nsf.end() );
|
|
|
|
|
+ Nf.insert( Nf.end(), Ndf.begin(), Ndf.end() );
|
|
|
|
|
+ // https://stackoverflow.com/a/1041939/148668
|
|
|
|
|
+ std::sort( Nf.begin(), Nf.end() );
|
|
|
|
|
+ Nf.erase( std::unique( Nf.begin(), Nf.end() ), Nf.end() );
|
|
|
|
|
+ // Collect all edges that must be updated
|
|
|
|
|
+ std::vector<int> Ne;
|
|
|
|
|
+ Ne.reserve(3*Nf.size());
|
|
|
|
|
+ for(auto & n : Nf)
|
|
|
{
|
|
{
|
|
|
if(F(n,0) != IGL_COLLAPSE_EDGE_NULL ||
|
|
if(F(n,0) != IGL_COLLAPSE_EDGE_NULL ||
|
|
|
F(n,1) != IGL_COLLAPSE_EDGE_NULL ||
|
|
F(n,1) != IGL_COLLAPSE_EDGE_NULL ||
|
|
@@ -371,24 +339,33 @@ IGL_INLINE bool igl::collapse_edge(
|
|
|
{
|
|
{
|
|
|
// get edge id
|
|
// get edge id
|
|
|
const int ei = EMAP(v*F.rows()+n);
|
|
const int ei = EMAP(v*F.rows()+n);
|
|
|
- // erase old entry
|
|
|
|
|
- Q.erase(Qit[ei]);
|
|
|
|
|
- // compute cost and potential placement
|
|
|
|
|
- double cost;
|
|
|
|
|
- RowVectorXd place;
|
|
|
|
|
- cost_and_placement(ei,V,F,E,EMAP,EF,EI,cost,place);
|
|
|
|
|
- // Replace in queue
|
|
|
|
|
- Qit[ei] = Q.insert(std::pair<double,int>(cost,ei)).first;
|
|
|
|
|
- C.row(ei) = place;
|
|
|
|
|
|
|
+ Ne.push_back(ei);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ // Only process edge once
|
|
|
|
|
+ std::sort( Ne.begin(), Ne.end() );
|
|
|
|
|
+ Ne.erase( std::unique( Ne.begin(), Ne.end() ), Ne.end() );
|
|
|
|
|
+ for(auto & ei : Ne)
|
|
|
|
|
+ {
|
|
|
|
|
+ // compute cost and potential placement
|
|
|
|
|
+ double cost;
|
|
|
|
|
+ RowVectorXd place;
|
|
|
|
|
+ cost_and_placement(ei,V,F,E,EMAP,EF,EI,cost,place);
|
|
|
|
|
+ // Increment timestamp
|
|
|
|
|
+ EQ(ei)++;
|
|
|
|
|
+ // Replace in queue
|
|
|
|
|
+ Q.emplace(cost,ei,EQ(ei));
|
|
|
|
|
+ C.row(ei) = place;
|
|
|
|
|
+ }
|
|
|
}else
|
|
}else
|
|
|
{
|
|
{
|
|
|
// reinsert with infinite weight (the provided cost function must **not**
|
|
// reinsert with infinite weight (the provided cost function must **not**
|
|
|
// have given this un-collapsable edge inf cost already)
|
|
// have given this un-collapsable edge inf cost already)
|
|
|
- p.first = std::numeric_limits<double>::infinity();
|
|
|
|
|
- Qit[e] = Q.insert(p).first;
|
|
|
|
|
|
|
+ // Increment timestamp
|
|
|
|
|
+ EQ(e)++;
|
|
|
|
|
+ // Replace in queue
|
|
|
|
|
+ Q.emplace(std::numeric_limits<double>::infinity(),e,EQ(e));
|
|
|
}
|
|
}
|
|
|
return collapsed;
|
|
return collapsed;
|
|
|
}
|
|
}
|