Revert templating on collapse_edge, separate overloads (#2455)

* Fix 2452

* fix cachev2 issue?

* and the windows ❄️

* removed __1::

* fix tutorial to use new func

* cmake bullshit
This commit is contained in:
Alec Jacobson
2025-03-31 17:00:36 -04:00
committed by GitHub
parent 5e561c28c8
commit 0e360d5250
10 changed files with 265 additions and 238 deletions
+6 -2
View File
@@ -60,7 +60,7 @@ jobs:
- name: Cache Build
id: cache-build
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: ~/.ccache
key: ${{ runner.os }}-${{ matrix.config }}-${{ matrix.build-params.static }}-cache
@@ -74,7 +74,9 @@ jobs:
run: |
mkdir -p build
cd build
# https://github.com/eclipse-ecal/ecal/issues/2041
cmake .. \
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_BUILD_TYPE=${{ matrix.config }} \
-DLIBIGL_USE_STATIC_LIBRARY=${{ matrix.build-params.static }} \
@@ -128,7 +130,7 @@ jobs:
- name: Cache build
id: cache-build
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: ${{ env.appdata }}\Mozilla\sccache
key: ${{ runner.os }}-${{ matrix.config }}-${{ matrix.build-params.static }}-cache
@@ -145,7 +147,9 @@ jobs:
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=x64
# https://github.com/eclipse-ecal/ecal/issues/2041
cmake -G Ninja ^
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 ^
-DCMAKE_CXX_COMPILER_LAUNCHER=sccache ^
-DCMAKE_BUILD_TYPE=${{ matrix.config }} ^
-DLIBIGL_USE_STATIC_LIBRARY=${{ matrix.build-params.static }} ^
+19
View File
@@ -0,0 +1,19 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2025 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/.
#ifndef IGL_COLLAPSE_EDGE_NULL_H
#define IGL_COLLAPSE_EDGE_NULL_H
namespace igl
{
#ifndef IGL_COLLAPSE_EDGE_NULL
/// Special value for indicating a null vertex index as the result of a
/// collapsed edge.
#define IGL_COLLAPSE_EDGE_NULL 0
#endif
}
#endif
+1 -155
View File
@@ -8,7 +8,6 @@
#include "collapse_edge.h"
#include "circulation.h"
#include "edge_collapse_is_valid.h"
#include "decimate_trivial_callbacks.h"
#include <vector>
template <
@@ -195,162 +194,9 @@ IGL_INLINE bool igl::collapse_edge(
return true;
}
template <
typename CPFunc,
typename PreFunc,
typename PostFunc,
typename DerivedV,
typename DerivedF,
typename DerivedE,
typename DerivedEMAP,
typename DerivedEF,
typename DerivedEI,
typename DerivedEQ,
typename DerivedC>
IGL_INLINE bool igl::collapse_edge(
const CPFunc & cost_and_placement,
const PreFunc & pre_collapse,
const PostFunc & post_collapse,
Eigen::MatrixBase<DerivedV> & V,
Eigen::MatrixBase<DerivedF> & F,
Eigen::MatrixBase<DerivedE> & E,
Eigen::MatrixBase<DerivedEMAP> & EMAP,
Eigen::MatrixBase<DerivedEF> & EF,
Eigen::MatrixBase<DerivedEI> & EI,
igl::min_heap< std::tuple<double,int,int> > & Q,
Eigen::MatrixBase<DerivedEQ> & EQ,
Eigen::MatrixBase<DerivedC> & C,
int & e,
int & e1,
int & e2,
int & f1,
int & f2)
{
using namespace Eigen;
using namespace igl;
std::tuple<double,int,int> p;
while(true)
{
// Check if Q is empty
if(Q.empty())
{
// no edges to collapse
e = -1;
return false;
}
// pop from Q
p = Q.top();
if(std::get<0>(p) == std::numeric_limits<double>::infinity())
{
e = -1;
// 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.
}
// 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;
if(pre_collapse(V,F,E,EMAP,EF,EI,Q,EQ,C,e))
{
collapsed = collapse_edge(
e,C.row(e),
Nsv,Nsf,Ndv,Ndf,
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,EQ,C,e,e1,e2,f1,f2,collapsed);
if(collapsed)
{
// Erase the center edge, marking its timestamp as -1
EQ(e) = -1;
// 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
// loop over original face neighbors
//
// 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 ||
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);
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
{
// reinsert with infinite weight (the provided cost function must **not**
// have given this un-collapsable edge inf cost already)
// Increment timestamp
EQ(e)++;
// Replace in queue
Q.emplace(std::numeric_limits<double>::infinity(),e,EQ(e));
}
return collapsed;
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template bool igl::collapse_edge<
std::function<void (int, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, double&, Eigen::Matrix<double, 1, -1, 1, 1, -1>&)>,
std::function<bool (Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, std::priority_queue<std::tuple<double, int, int>, std::vector<std::tuple<double, int, int>, std::allocator<std::tuple<double, int, int>>>, std::greater<std::tuple<double, int, int>>> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, int)>,
std::function<void (Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, std::priority_queue<std::tuple<double, int, int>, std::vector<std::tuple<double, int, int>, std::allocator<std::tuple<double, int, int>>>, std::greater<std::tuple<double, int, int>>> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, int, int, int, int, int, bool)>,
Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>>(std::function<void (int, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, double&, Eigen::Matrix<double, 1, -1, 1, 1, -1>&)> const&, std::function<bool (Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, std::priority_queue<std::tuple<double, int, int>, std::vector<std::tuple<double, int, int>, std::allocator<std::tuple<double, int, int>>>, std::greater<std::tuple<double, int, int>>> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, int)> const&, std::function<void (Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, std::priority_queue<std::tuple<double, int, int>, std::vector<std::tuple<double, int, int>, std::allocator<std::tuple<double, int, int>>>, std::greater<std::tuple<double, int, int>>> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, int, int, int, int, int, bool)> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&, std::priority_queue<std::tuple<double, int, int>, std::vector<std::tuple<double, int, int>, std::allocator<std::tuple<double, int, int>>>, std::greater<std::tuple<double, int, int>>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1>>&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>>&, int&, int&, int&, int&, int&);
template bool igl::collapse_edge<Eigen::Matrix<double, 1, -1, 1, 1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>>(int, Eigen::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1>> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&, int&, int&, int&, int&);
template bool igl::collapse_edge<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 1, -1, false>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>>(int, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 1, -1, false>> const&, std::vector<int, std::allocator<int>>&, std::vector<int, std::allocator<int>> const&, std::vector<int, std::allocator<int>>&, std::vector<int, std::allocator<int>> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&, int&, int&, int&, int&);
#endif
+1 -74
View File
@@ -8,18 +8,11 @@
#ifndef IGL_COLLAPSE_EDGE_H
#define IGL_COLLAPSE_EDGE_H
#include "igl_inline.h"
#include "min_heap.h"
#include "decimate_callback_types.h"
#include "COLLAPSE_EDGE_NULL.h"
#include <Eigen/Core>
#include <vector>
#include <set>
namespace igl
{
#ifndef IGL_COLLAPSE_EDGE_NULL
/// Special value for indicating a null vertex index as the result of a
/// collapsed edge.
#define IGL_COLLAPSE_EDGE_NULL 0
#endif
/// Attempt to collapse a given edge of a mesh. Assumes (V,F) is a closed
/// manifold mesh (except for previously collapsed faces which should be set
/// to: [IGL_COLLAPSE_EDGE_NULL IGL_COLLAPSE_EDGE_NULL
@@ -161,72 +154,6 @@ namespace igl
int & a_e2,
int & a_f1,
int & a_f2);
/// Collapse least-cost edge from a priority queue and update queue
///
/// See decimate.h for more details.
///
/// @param[in] cost_and_placement function computing cost of collapsing an edge and 3d
/// position where it should be placed:
/// cost_and_placement(V,F,E,EMAP,EF,EI,cost,placement);
/// **If the edges is collapsed** then this function will be called on all
/// edges of all faces previously incident on the endpoints of the
/// collapsed edge.
/// @param[in] pre_collapse callback called with index of edge whose collapse is about
/// to be attempted. This function should return whether to **proceed**
/// with the collapse: returning true means "yes, try to collapse",
/// returning false means "No, consider this edge 'uncollapsable', behave
/// as if collapse_edge(e) returned false.
/// @param[in] post_collapse callback called with index of edge whose collapse was
/// just attempted and a flag revealing whether this was successful.
/// @param[in,out] V #V by dim list of vertex positions, lesser index of E(e,:) will be set
/// to midpoint of edge.
/// @param[in,out] F #F by 3 list of face indices into V.
/// @param[in,out] E #E by 2 list of edge indices into V.
/// @param[in,out] EMAP #F*3 list of indices into E, mapping each directed edge to unique
/// unique edge in E
/// @param[in,out] EF #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of
/// F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1)
/// e=(j->i)
/// @param[in,out] EI #E by 2 list of edge flap corners (see above).
/// @param[in] Q queue containing pairs of costs and edge indices and insertion "time"
/// @param[in] EQ #E list of "time" of last time pushed into Q
/// @param[in] C #E by dim list of stored placements
/// @param[out] e index into E of attempted collapsed edge. Set to -1 if Q is empty or
/// contains only infinite cost edges.
/// @param[out] e1 index into E of edge collpased on left.
/// @param[out] e2 index into E of edge collpased on right.
/// @param[out] f1 index into F of face collpased on left.
/// @param[out] f2 index into F of face collpased on right.
template <
typename CPFunc,
typename PreFunc,
typename PostFunc,
typename DerivedV,
typename DerivedF,
typename DerivedE,
typename DerivedEMAP,
typename DerivedEF,
typename DerivedEI,
typename DerivedEQ,
typename DerivedC>
IGL_INLINE bool collapse_edge(
const CPFunc & cost_and_placement,
const PreFunc & pre_collapse,
const PostFunc & post_collapse,
Eigen::MatrixBase<DerivedV> & V,
Eigen::MatrixBase<DerivedF> & F,
Eigen::MatrixBase<DerivedE> & E,
Eigen::MatrixBase<DerivedEMAP> & EMAP,
Eigen::MatrixBase<DerivedEF> & EF,
Eigen::MatrixBase<DerivedEI> & EI,
igl::min_heap< std::tuple<double,int,int> > & Q,
Eigen::MatrixBase<DerivedEQ> & EQ,
Eigen::MatrixBase<DerivedC> & C,
int & e,
int & e1,
int & e2,
int & f1,
int & f2);
}
#ifndef IGL_STATIC_LIBRARY
+148
View File
@@ -0,0 +1,148 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2025 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_least_cost_edge.h"
#include "collapse_edge.h"
#include "circulation.h"
IGL_INLINE bool igl::collapse_least_cost_edge(
const decimate_cost_and_placement_callback & cost_and_placement,
const decimate_pre_collapse_callback & pre_collapse,
const decimate_post_collapse_callback & post_collapse,
Eigen::MatrixXd & V,
Eigen::MatrixXi & F,
Eigen::MatrixXi & E,
Eigen::VectorXi & EMAP,
Eigen::MatrixXi & EF,
Eigen::MatrixXi & EI,
igl::min_heap< std::tuple<double,int,int> > & Q,
Eigen::VectorXi & EQ,
Eigen::MatrixXd & C,
int & e,
int & e1,
int & e2,
int & f1,
int & f2)
{
using namespace Eigen;
using namespace igl;
std::tuple<double,int,int> p;
while(true)
{
// Check if Q is empty
if(Q.empty())
{
// no edges to collapse
e = -1;
return false;
}
// pop from Q
p = Q.top();
if(std::get<0>(p) == std::numeric_limits<double>::infinity())
{
e = -1;
// 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.
}
// 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;
if(pre_collapse(V,F,E,EMAP,EF,EI,Q,EQ,C,e))
{
collapsed = collapse_edge(
e,C.row(e),
Nsv,Nsf,Ndv,Ndf,
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,EQ,C,e,e1,e2,f1,f2,collapsed);
if(collapsed)
{
// Erase the center edge, marking its timestamp as -1
EQ(e) = -1;
// 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
// loop over original face neighbors
//
// 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 ||
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);
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
{
// reinsert with infinite weight (the provided cost function must **not**
// have given this un-collapsable edge inf cost already)
// Increment timestamp
EQ(e)++;
// Replace in queue
Q.emplace(std::numeric_limits<double>::infinity(),e,EQ(e));
}
return collapsed;
}
+82
View File
@@ -0,0 +1,82 @@
// 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/.
#ifndef IGL_COLLAPSE_LEAST_COST_EDGE_H
#define IGL_COLLAPSE_LEAST_COST_EDGE_H
#include "igl_inline.h"
#include "min_heap.h"
#include "decimate_callback_types.h"
#include "COLLAPSE_EDGE_NULL.h"
#include <Eigen/Core>
#include <vector>
namespace igl
{
/// Collapse least-cost edge from a priority queue and update queue
///
/// See decimate.h for more details.
///
/// @param[in] cost_and_placement function computing cost of collapsing an edge and 3d
/// position where it should be placed:
/// cost_and_placement(V,F,E,EMAP,EF,EI,cost,placement);
/// **If the edges is collapsed** then this function will be called on all
/// edges of all faces previously incident on the endpoints of the
/// collapsed edge.
/// @param[in] pre_collapse callback called with index of edge whose collapse is about
/// to be attempted. This function should return whether to **proceed**
/// with the collapse: returning true means "yes, try to collapse",
/// returning false means "No, consider this edge 'uncollapsable', behave
/// as if collapse_edge(e) returned false.
/// @param[in] post_collapse callback called with index of edge whose collapse was
/// just attempted and a flag revealing whether this was successful.
/// @param[in,out] V #V by dim list of vertex positions, lesser index of E(e,:) will be set
/// to midpoint of edge.
/// @param[in,out] F #F by 3 list of face indices into V.
/// @param[in,out] E #E by 2 list of edge indices into V.
/// @param[in,out] EMAP #F*3 list of indices into E, mapping each directed edge to unique
/// unique edge in E
/// @param[in,out] EF #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of
/// F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1)
/// e=(j->i)
/// @param[in,out] EI #E by 2 list of edge flap corners (see above).
/// @param[in] Q queue containing pairs of costs and edge indices and insertion "time"
/// @param[in] EQ #E list of "time" of last time pushed into Q
/// @param[in] C #E by dim list of stored placements
/// @param[out] e index into E of attempted collapsed edge. Set to -1 if Q is empty or
/// contains only infinite cost edges.
/// @param[out] e1 index into E of edge collpased on left.
/// @param[out] e2 index into E of edge collpased on right.
/// @param[out] f1 index into F of face collpased on left.
/// @param[out] f2 index into F of face collpased on right.
///
/// \bug This function is not templated nicely and refactoring it and its
/// dependencies to do so is non-trivial, see
/// https://github.com/libigl/libigl/issues/2452
IGL_INLINE bool collapse_least_cost_edge(
const decimate_cost_and_placement_callback & cost_and_placement,
const decimate_pre_collapse_callback & pre_collapse,
const decimate_post_collapse_callback & post_collapse,
Eigen::MatrixXd & V,
Eigen::MatrixXi & F,
Eigen::MatrixXi & E,
Eigen::VectorXi & EMAP,
Eigen::MatrixXi & EF,
Eigen::MatrixXi & EI,
igl::min_heap< std::tuple<double,int,int> > & Q,
Eigen::VectorXi & EQ,
Eigen::MatrixXd & C,
int & e,
int & e1,
int & e2,
int & f1,
int & f2);
}
#ifndef IGL_STATIC_LIBRARY
# include "collapse_least_cost_edge.cpp"
#endif
#endif
+2 -2
View File
@@ -6,7 +6,7 @@
// 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 "collapse_least_cost_edge.h"
#include "edge_flaps.h"
#include "decimate_trivial_callbacks.h"
#include "AABB.h"
@@ -167,7 +167,7 @@ IGL_INLINE bool igl::decimate(
while(true)
{
int e,e1,e2,f1,f2;
if(collapse_edge(
if(collapse_least_cost_edge(
cost_and_placement, pre_collapse, post_collapse,
V,F,E,EMAP,EF,EI,Q,EQ,C,e,e1,e2,f1,f2))
{
+4 -2
View File
@@ -9,6 +9,7 @@
#define IGL_DECIMATE_H
#include "igl_inline.h"
#include "decimate_callback_types.h"
#include "COLLAPSE_EDGE_NULL.h"
#include <Eigen/Core>
/// @file decimate.h
@@ -68,6 +69,7 @@
/// users threshold).
///
/// \see
/// collapse_least_cost_edge
/// collapse_edge
/// qslim
@@ -119,10 +121,10 @@ namespace igl
/// bool should_stop =
/// stopping_condition(V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2);
/// @param[in] pre_collapse callback called with index of edge whose collapse is about
/// to be attempted (see collapse_edge)
/// to be attempted (see collapse_least_cost_edge)
/// @param[in] post_collapse callback called with index of edge whose collapse was
/// just attempted and a flag revealing whether this was successful (see
/// collapse_edge)
/// collapse_least_cost_edge)
/// @param[out] U #U by dim list of output vertex posistions (can be same ref as V)
/// @param[out] G #G by 3 list of output face indices into U (can be same ref as G)
/// @param[out] J #G list of indices into F of birth face
-1
View File
@@ -7,7 +7,6 @@
// obtain one at http://mozilla.org/MPL/2.0/.
#include "qslim.h"
#include "collapse_edge.h"
#include "connect_boundary_to_infinity.h"
#include "decimate.h"
#include "edge_flaps.h"
+2 -2
View File
@@ -1,5 +1,5 @@
#include <igl/circulation.h>
#include <igl/collapse_edge.h>
#include <igl/collapse_least_cost_edge.h>
#include <igl/edge_flaps.h>
#include <igl/decimate.h>
#include <igl/shortest_edge_and_midpoint.h>
@@ -92,7 +92,7 @@ int main(int argc, char * argv[])
// Only relevant if IGL_STATIC_LIBRARY is defined
const std::function<void (int, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, double&, Eigen::Matrix<double, 1, -1, 1, 1, -1>&)> cp = shortest_edge_and_midpoint;
int e,e1,e2,f1,f2;
if(!collapse_edge(
if(!collapse_least_cost_edge(
cp,always_try,never_care,
V,F,E,
EMAP,EF,EI,