OrcaSlicer/src/libigl/igl/collapse_edge.cpp
tamasmeszaros 2ae2672ee9 Building igl statically and moving to the dep scripts
Fixing dep build script on Windows and removing some warnings.

Use bundled igl by default.

Not building with the dependency scripts if not explicitly stated. This way, it will stay in
Fix the libigl patch to include C source files in header only mode.
2019-06-19 14:52:55 +02:00

394 lines
14 KiB
C++

// 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 "collapse_edge.h"
#include "circulation.h"
#include "edge_collapse_is_valid.h"
#include <vector>
IGL_INLINE bool igl::collapse_edge(
const int e,
const Eigen::RowVectorXd & p,
Eigen::MatrixXd & V,
Eigen::MatrixXi & F,
Eigen::MatrixXi & E,
Eigen::VectorXi & EMAP,
Eigen::MatrixXi & EF,
Eigen::MatrixXi & EI,
int & a_e1,
int & a_e2,
int & a_f1,
int & a_f2)
{
// Assign this to 0 rather than, say, -1 so that deleted elements will get
// draw as degenerate elements at vertex 0 (which should always exist and
// never get collapsed to anything else since it is the smallest index)
using namespace Eigen;
using namespace std;
const int eflip = E(e,0)>E(e,1);
// source and destination
const int s = eflip?E(e,1):E(e,0);
const int d = eflip?E(e,0):E(e,1);
if(!edge_collapse_is_valid(e,F,E,EMAP,EF,EI))
{
return false;
}
// Important to grab neighbors of d before monkeying with edges
const std::vector<int> nV2Fd = circulation(e,!eflip,F,E,EMAP,EF,EI);
// The following implementation strongly relies on s<d
assert(s<d && "s should be less than d");
// move source and destination to midpoint
V.row(s) = p;
V.row(d) = p;
// Helper function to replace edge and associate information with NULL
const auto & kill_edge = [&E,&EI,&EF](const int e)
{
E(e,0) = IGL_COLLAPSE_EDGE_NULL;
E(e,1) = IGL_COLLAPSE_EDGE_NULL;
EF(e,0) = IGL_COLLAPSE_EDGE_NULL;
EF(e,1) = IGL_COLLAPSE_EDGE_NULL;
EI(e,0) = IGL_COLLAPSE_EDGE_NULL;
EI(e,1) = IGL_COLLAPSE_EDGE_NULL;
};
// update edge info
// for each flap
const int m = F.rows();
for(int side = 0;side<2;side++)
{
const int f = EF(e,side);
const int v = EI(e,side);
const int sign = (eflip==0?1:-1)*(1-2*side);
// next edge emanating from d
const int e1 = EMAP(f+m*((v+sign*1+3)%3));
// prev edge pointing to s
const int e2 = EMAP(f+m*((v+sign*2+3)%3));
assert(E(e1,0) == d || E(e1,1) == d);
assert(E(e2,0) == s || E(e2,1) == s);
// face adjacent to f on e1, also incident on d
const bool flip1 = EF(e1,1)==f;
const int f1 = flip1 ? EF(e1,0) : EF(e1,1);
assert(f1!=f);
assert(F(f1,0)==d || F(f1,1)==d || F(f1,2) == d);
// across from which vertex of f1 does e1 appear?
const int v1 = flip1 ? EI(e1,0) : EI(e1,1);
// Kill e1
kill_edge(e1);
// Kill f
F(f,0) = IGL_COLLAPSE_EDGE_NULL;
F(f,1) = IGL_COLLAPSE_EDGE_NULL;
F(f,2) = IGL_COLLAPSE_EDGE_NULL;
// map f1's edge on e1 to e2
assert(EMAP(f1+m*v1) == e1);
EMAP(f1+m*v1) = e2;
// side opposite f2, the face adjacent to f on e2, also incident on s
const int opp2 = (EF(e2,0)==f?0:1);
assert(EF(e2,opp2) == f);
EF(e2,opp2) = f1;
EI(e2,opp2) = v1;
// remap e2 from d to s
E(e2,0) = E(e2,0)==d ? s : E(e2,0);
E(e2,1) = E(e2,1)==d ? s : E(e2,1);
if(side==0)
{
a_e1 = e1;
a_f1 = f;
}else
{
a_e2 = e1;
a_f2 = f;
}
}
// finally, reindex faces and edges incident on d. Do this last so asserts
// make sense.
//
// Could actually skip first and last, since those are always the two
// collpased faces.
for(auto f : nV2Fd)
{
for(int v = 0;v<3;v++)
{
if(F(f,v) == d)
{
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;
}
}
}
// Finally, "remove" this edge and its information
kill_edge(e);
return true;
}
IGL_INLINE bool igl::collapse_edge(
const int e,
const Eigen::RowVectorXd & p,
Eigen::MatrixXd & V,
Eigen::MatrixXi & F,
Eigen::MatrixXi & E,
Eigen::VectorXi & EMAP,
Eigen::MatrixXi & EF,
Eigen::MatrixXi & EI)
{
int e1,e2,f1,f2;
return collapse_edge(e,p,V,F,E,EMAP,EF,EI,e1,e2,f1,f2);
}
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,
Eigen::MatrixXd & V,
Eigen::MatrixXi & F,
Eigen::MatrixXi & E,
Eigen::VectorXi & EMAP,
Eigen::MatrixXi & EF,
Eigen::MatrixXi & EI,
std::set<std::pair<double,int> > & Q,
std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
Eigen::MatrixXd & C)
{
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 { };
return
collapse_edge(
cost_and_placement,always_try,never_care,
V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2);
}
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,
Eigen::MatrixXd & V,
Eigen::MatrixXi & F,
Eigen::MatrixXi & E,
Eigen::VectorXi & EMAP,
Eigen::MatrixXi & EF,
Eigen::MatrixXi & EI,
std::set<std::pair<double,int> > & Q,
std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
Eigen::MatrixXd & C)
{
int e,e1,e2,f1,f2;
return
collapse_edge(
cost_and_placement,pre_collapse,post_collapse,
V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2);
}
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,
Eigen::MatrixXd & V,
Eigen::MatrixXi & F,
Eigen::MatrixXi & E,
Eigen::VectorXi & EMAP,
Eigen::MatrixXi & EF,
Eigen::MatrixXi & EI,
std::set<std::pair<double,int> > & Q,
std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
Eigen::MatrixXd & C,
int & e,
int & e1,
int & e2,
int & f1,
int & f2)
{
using namespace Eigen;
if(Q.empty())
{
// 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;
}
Q.erase(Q.begin());
e = p.second;
Qit[e] = Q.end();
std::vector<int> N = circulation(e, true,F,E,EMAP,EF,EI);
std::vector<int> Nd = circulation(e,false,F,E,EMAP,EF,EI);
N.insert(N.begin(),Nd.begin(),Nd.end());
bool collapsed = true;
if(pre_collapse(V,F,E,EMAP,EF,EI,Q,Qit,C,e))
{
collapsed = collapse_edge(e,C.row(e),V,F,E,EMAP,EF,EI,e1,e2,f1,f2);
}else
{
// Aborted by pre collapse callback
collapsed = false;
}
post_collapse(V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2,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();
// update local neighbors
// loop over original face neighbors
for(auto n : N)
{
if(F(n,0) != IGL_COLLAPSE_EDGE_NULL ||
F(n,1) != IGL_COLLAPSE_EDGE_NULL ||
F(n,2) != IGL_COLLAPSE_EDGE_NULL)
{
for(int v = 0;v<3;v++)
{
// get edge id
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;
}
}
}
}else
{
// reinsert with infinite weight (the provided cost function must **not**
// have given this un-collapsable edge inf cost already)
p.first = std::numeric_limits<double>::infinity();
Qit[e] = Q.insert(p).first;
}
return collapsed;
}