Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3283e29b7 | ||
|
|
261fec1d05 | ||
|
|
ab6229c77a | ||
|
|
b1fe6ba49c | ||
|
|
8d940367bf |
@@ -1,51 +1,2 @@
|
||||
function(igl_add_test module_name)
|
||||
if(NOT LIBIGL_BUILD_TESTS)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET ${module_name})
|
||||
message(FATAL_ERROR "'${module_name}' is not a CMake target")
|
||||
endif()
|
||||
|
||||
# Check if category is `copyleft` or `restricted`
|
||||
if(${module_name} MATCHES "^igl_copyleft")
|
||||
set(suffix "_copyleft")
|
||||
elseif(${module_name} MATCHES "^igl_restricted")
|
||||
set(suffix "_restricted")
|
||||
else()
|
||||
set(suffix "")
|
||||
endif()
|
||||
|
||||
# Create test executable
|
||||
add_executable(test_${module_name}
|
||||
${libigl_SOURCE_DIR}/tests/main.cpp
|
||||
${libigl_SOURCE_DIR}/tests/test_common.h
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
# Include headers
|
||||
target_include_directories(test_${module_name} PUBLIC ${libigl_SOURCE_DIR}/tests)
|
||||
|
||||
# Compile definitions
|
||||
target_compile_definitions(test_${module_name} PUBLIC CATCH_CONFIG_ENABLE_BENCHMARKING)
|
||||
|
||||
# Dependencies
|
||||
include(catch2)
|
||||
include(libigl_tests_data)
|
||||
target_link_libraries(test_${module_name} PUBLIC
|
||||
${module_name}
|
||||
igl::tests_data
|
||||
Catch2::Catch2
|
||||
)
|
||||
|
||||
# IDE Folder
|
||||
set_target_properties(test_${module_name} PROPERTIES FOLDER Libigl_Tests)
|
||||
|
||||
# Output directory
|
||||
set_target_properties(test_${module_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
|
||||
|
||||
# Register tests
|
||||
FetchContent_GetProperties(catch2)
|
||||
include("${catch2_SOURCE_DIR}/contrib/Catch.cmake")
|
||||
catch_discover_tests(test_${module_name})
|
||||
endfunction()
|
||||
|
||||
@@ -13,22 +13,3 @@ include(igl_windows)
|
||||
|
||||
# Libigl permissive modules
|
||||
igl_include(core)
|
||||
igl_include_optional(embree)
|
||||
igl_include_optional(opengl)
|
||||
igl_include_optional(glfw)
|
||||
igl_include_optional(imgui)
|
||||
igl_include_optional(predicates)
|
||||
igl_include_optional(stb)
|
||||
igl_include_optional(spectra)
|
||||
igl_include_optional(xml)
|
||||
|
||||
# Libigl copyleft modules
|
||||
igl_include_optional(copyleft core)
|
||||
igl_include_optional(copyleft cgal)
|
||||
igl_include_optional(copyleft comiso)
|
||||
igl_include_optional(copyleft tetgen)
|
||||
|
||||
# Libigl restricted modules
|
||||
igl_include_optional(restricted matlab)
|
||||
igl_include_optional(restricted mosek)
|
||||
igl_include_optional(restricted triangle)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,130 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2017 Daniele Panozzo <daniele.panozzo@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 "AtA_cached.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
template <typename Scalar>
|
||||
IGL_INLINE void igl::AtA_cached_precompute(
|
||||
const Eigen::SparseMatrix<Scalar>& A,
|
||||
igl::AtA_cached_data& data,
|
||||
Eigen::SparseMatrix<Scalar>& AtA)
|
||||
{
|
||||
// 1 Compute At (this could be avoided, but performance-wise it will not make a difference)
|
||||
std::vector<std::vector<int> > Col_RowPtr;
|
||||
std::vector<std::vector<int> > Col_IndexPtr;
|
||||
|
||||
Col_RowPtr.resize(A.cols());
|
||||
Col_IndexPtr.resize(A.cols());
|
||||
|
||||
for (unsigned k=0; k<A.outerSize(); ++k)
|
||||
{
|
||||
unsigned outer_index = *(A.outerIndexPtr()+k);
|
||||
unsigned next_outer_index = (k+1 == A.outerSize()) ? A.nonZeros() : *(A.outerIndexPtr()+k+1);
|
||||
|
||||
for (unsigned l=outer_index; l<next_outer_index; ++l)
|
||||
{
|
||||
int col = k;
|
||||
int row = *(A.innerIndexPtr()+l);
|
||||
int value_index = l;
|
||||
assert(col < A.cols());
|
||||
assert(col >= 0);
|
||||
assert(row < A.rows());
|
||||
assert(row >= 0);
|
||||
assert(value_index >= 0);
|
||||
assert(value_index < A.nonZeros());
|
||||
|
||||
Col_RowPtr[col].push_back(row);
|
||||
Col_IndexPtr[col].push_back(value_index);
|
||||
}
|
||||
}
|
||||
|
||||
Eigen::SparseMatrix<Scalar> At = A.transpose();
|
||||
At.makeCompressed();
|
||||
AtA = At * A;
|
||||
AtA.makeCompressed();
|
||||
|
||||
assert(AtA.isCompressed());
|
||||
|
||||
// If weights are not provided, use 1
|
||||
if (data.W.size() == 0)
|
||||
data.W = Eigen::VectorXd::Ones(A.rows());
|
||||
assert(data.W.size() == A.rows());
|
||||
|
||||
data.I_outer.reserve(AtA.outerSize());
|
||||
data.I_row.reserve(2*AtA.nonZeros());
|
||||
data.I_col.reserve(2*AtA.nonZeros());
|
||||
data.I_w.reserve(2*AtA.nonZeros());
|
||||
|
||||
// 2 Construct the rules
|
||||
for (unsigned k=0; k<AtA.outerSize(); ++k)
|
||||
{
|
||||
unsigned outer_index = *(AtA.outerIndexPtr()+k);
|
||||
unsigned next_outer_index = (k+1 == AtA.outerSize()) ? AtA.nonZeros() : *(AtA.outerIndexPtr()+k+1);
|
||||
|
||||
for (unsigned l=outer_index; l<next_outer_index; ++l)
|
||||
{
|
||||
int col = k;
|
||||
int row = *(AtA.innerIndexPtr()+l);
|
||||
int value_index = l;
|
||||
assert(col < AtA.cols());
|
||||
assert(col >= 0);
|
||||
assert(row < AtA.rows());
|
||||
assert(row >= 0);
|
||||
assert(value_index >= 0);
|
||||
assert(value_index < AtA.nonZeros());
|
||||
|
||||
data.I_outer.push_back(data.I_row.size());
|
||||
|
||||
// Find correspondences
|
||||
unsigned i=0;
|
||||
unsigned j=0;
|
||||
while (i<Col_RowPtr[row].size() && j<Col_RowPtr[col].size())
|
||||
{
|
||||
if (Col_RowPtr[row][i] == Col_RowPtr[col][j])
|
||||
{
|
||||
data.I_row.push_back(Col_IndexPtr[row][i]);
|
||||
data.I_col.push_back(Col_IndexPtr[col][j]);
|
||||
data.I_w.push_back(Col_RowPtr[col][j]);
|
||||
++i;
|
||||
++j;
|
||||
} else
|
||||
if (Col_RowPtr[row][i] > Col_RowPtr[col][j])
|
||||
++j;
|
||||
else
|
||||
++i;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
data.I_outer.push_back(data.I_row.size()); // makes it more efficient to iterate later on
|
||||
|
||||
igl::AtA_cached(A,data,AtA);
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
IGL_INLINE void igl::AtA_cached(
|
||||
const Eigen::SparseMatrix<Scalar>& A,
|
||||
const igl::AtA_cached_data& data,
|
||||
Eigen::SparseMatrix<Scalar>& AtA)
|
||||
{
|
||||
for (unsigned i=0; i<data.I_outer.size()-1; ++i)
|
||||
{
|
||||
*(AtA.valuePtr() + i) = 0;
|
||||
for (unsigned j=data.I_outer[i]; j<data.I_outer[i+1]; ++j)
|
||||
*(AtA.valuePtr() + i) += *(A.valuePtr() + data.I_row[j]) * data.W[data.I_w[j]] * *(A.valuePtr() + data.I_col[j]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
template void igl::AtA_cached<double>(Eigen::SparseMatrix<double, 0, int> const&, igl::AtA_cached_data const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
template void igl::AtA_cached_precompute<double>(Eigen::SparseMatrix<double, 0, int> const&, igl::AtA_cached_data&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
#endif
|
||||
@@ -1,30 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "EPS.h"
|
||||
|
||||
template <> IGL_INLINE float igl::EPS()
|
||||
{
|
||||
return igl::FLOAT_EPS;
|
||||
}
|
||||
template <> IGL_INLINE double igl::EPS()
|
||||
{
|
||||
return igl::DOUBLE_EPS;
|
||||
}
|
||||
|
||||
template <> IGL_INLINE float igl::EPS_SQ()
|
||||
{
|
||||
return igl::FLOAT_EPS_SQ;
|
||||
}
|
||||
template <> IGL_INLINE double igl::EPS_SQ()
|
||||
{
|
||||
return igl::DOUBLE_EPS_SQ;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
#endif
|
||||
@@ -1,162 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@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 "HalfEdgeIterator.h"
|
||||
|
||||
template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
|
||||
IGL_INLINE igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::HalfEdgeIterator(
|
||||
const Eigen::MatrixBase<DerivedF>& _F,
|
||||
const Eigen::MatrixBase<DerivedFF>& _FF,
|
||||
const Eigen::MatrixBase<DerivedFFi>& _FFi,
|
||||
int _fi,
|
||||
int _ei,
|
||||
bool _reverse
|
||||
)
|
||||
: fi(_fi), ei(_ei), reverse(_reverse), F(_F), FF(_FF), FFi(_FFi)
|
||||
{}
|
||||
|
||||
template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
|
||||
IGL_INLINE void igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::flipF()
|
||||
{
|
||||
if (isBorder())
|
||||
return;
|
||||
|
||||
int fin = (FF)(fi,ei);
|
||||
int ein = (FFi)(fi,ei);
|
||||
|
||||
fi = fin;
|
||||
ei = ein;
|
||||
reverse = !reverse;
|
||||
}
|
||||
|
||||
|
||||
// Change Edge
|
||||
template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
|
||||
IGL_INLINE void igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::flipE()
|
||||
{
|
||||
if (!reverse)
|
||||
ei = (ei+2)%3; // ei-1
|
||||
else
|
||||
ei = (ei+1)%3;
|
||||
|
||||
reverse = !reverse;
|
||||
}
|
||||
|
||||
// Change Vertex
|
||||
template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
|
||||
IGL_INLINE void igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::flipV()
|
||||
{
|
||||
reverse = !reverse;
|
||||
}
|
||||
|
||||
template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
|
||||
IGL_INLINE bool igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::isBorder()
|
||||
{
|
||||
return (FF)(fi,ei) == -1;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Returns the next edge skipping the border
|
||||
* _________
|
||||
* /\ c | b /\
|
||||
* / \ | / \
|
||||
* / d \ | / a \
|
||||
* /______\|/______\
|
||||
* v
|
||||
* In this example, if a and d are of-border and the pos is iterating counterclockwise, this method iterate through the faces incident on vertex v,
|
||||
* producing the sequence a, b, c, d, a, b, c, ...
|
||||
*/
|
||||
template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
|
||||
IGL_INLINE bool igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::NextFE()
|
||||
{
|
||||
if ( isBorder() ) // we are on a border
|
||||
{
|
||||
do
|
||||
{
|
||||
flipF();
|
||||
flipE();
|
||||
} while (!isBorder());
|
||||
flipE();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
flipF();
|
||||
flipE();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Get vertex index
|
||||
template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
|
||||
IGL_INLINE int igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::Vi()
|
||||
{
|
||||
assert(fi >= 0);
|
||||
assert(fi < F.rows());
|
||||
assert(ei >= 0);
|
||||
assert(ei <= 2);
|
||||
|
||||
if (!reverse)
|
||||
return (F)(fi,ei);
|
||||
else
|
||||
return (F)(fi,(ei+1)%3);
|
||||
}
|
||||
|
||||
// Get face index
|
||||
template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
|
||||
IGL_INLINE int igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::Fi()
|
||||
{
|
||||
return fi;
|
||||
}
|
||||
|
||||
// Get edge index
|
||||
template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
|
||||
IGL_INLINE int igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::Ei()
|
||||
{
|
||||
return ei;
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
|
||||
IGL_INLINE bool igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::operator==(HalfEdgeIterator& p2)
|
||||
{
|
||||
return
|
||||
(
|
||||
(fi == p2.fi) &&
|
||||
(ei == p2.ei) &&
|
||||
(reverse == p2.reverse) &&
|
||||
(F == p2.F) &&
|
||||
(FF == p2.FF) &&
|
||||
(FFi == p2.FFi)
|
||||
);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> >::HalfEdgeIterator(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, int, int, bool);
|
||||
template igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::HalfEdgeIterator(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, int, bool);
|
||||
template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::NextFE();
|
||||
template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Ei();
|
||||
template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Ei();
|
||||
template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> >::Ei();
|
||||
template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> >::Fi();
|
||||
template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> >::NextFE();
|
||||
template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Vi();
|
||||
template igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::HalfEdgeIterator(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, int, bool);
|
||||
template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Fi();
|
||||
template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::flipE();
|
||||
template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >::flipE();
|
||||
template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::flipF();
|
||||
template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >::flipF();
|
||||
template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::flipV();
|
||||
template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::operator==(igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Fi();
|
||||
template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::NextFE();
|
||||
template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >::isBorder();
|
||||
template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::isBorder();
|
||||
#endif
|
||||
@@ -1,497 +0,0 @@
|
||||
// based on MSH reader from PyMesh
|
||||
|
||||
// Copyright (c) 2015 Qingnan Zhou <qzhou@adobe.com>
|
||||
// Copyright (C) 2020 Vladimir Fonov <vladimir.fonov@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 "MshLoader.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace igl {
|
||||
// helper function
|
||||
void inline _msh_eat_white_space(std::ifstream& fin) {
|
||||
char next = fin.peek();
|
||||
while (next == '\n' || next == ' ' || next == '\t' || next == '\r') {
|
||||
fin.get();
|
||||
next = fin.peek();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE igl::MshLoader::MshLoader(const std::string &filename) {
|
||||
std::ifstream fin(filename, std::ios::in | std::ios::binary);
|
||||
|
||||
if (!fin.is_open()) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "failed to open file \"" << filename << "\"";
|
||||
throw std::ios_base::failure(err_msg.str());
|
||||
}
|
||||
// Parse header
|
||||
std::string buf;
|
||||
double version;
|
||||
int type;
|
||||
fin >> buf;
|
||||
if (buf != "$MeshFormat") { throw std::runtime_error("Unexpected .msh format"); }
|
||||
|
||||
fin >> version >> type >> m_data_size;
|
||||
m_binary = (type == 1);
|
||||
if(version>2.2 || version<2.0)
|
||||
{
|
||||
// probably unsupported version
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Error: Unsupported file version:" << version << std::endl;
|
||||
throw std::runtime_error(err_msg.str());
|
||||
|
||||
}
|
||||
// Some sanity check.
|
||||
if (m_data_size != 8) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Error: data size must be 8 bytes." << std::endl;
|
||||
throw std::runtime_error(err_msg.str());
|
||||
}
|
||||
if (sizeof(int) != 4) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Error: code must be compiled with int size 4 bytes." << std::endl;
|
||||
throw std::runtime_error(err_msg.str());
|
||||
}
|
||||
|
||||
// Read in extra info from binary header.
|
||||
if (m_binary) {
|
||||
int one;
|
||||
igl::_msh_eat_white_space(fin);
|
||||
fin.read(reinterpret_cast<char*>(&one), sizeof(int));
|
||||
if (one != 1) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Binary msh file " << filename
|
||||
<< " is saved with different endianness than this machine."
|
||||
<< std::endl;
|
||||
throw std::runtime_error(err_msg.str());
|
||||
}
|
||||
}
|
||||
|
||||
fin >> buf;
|
||||
if (buf != "$EndMeshFormat")
|
||||
{
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Unexpected contents in the file header." << std::endl;
|
||||
throw std::runtime_error(err_msg.str());
|
||||
}
|
||||
|
||||
while (!fin.eof()) {
|
||||
buf.clear();
|
||||
fin >> buf;
|
||||
if (buf == "$Nodes") {
|
||||
parse_nodes(fin);
|
||||
fin >> buf;
|
||||
if (buf != "$EndNodes") { throw std::runtime_error("Unexpected tag"); }
|
||||
} else if (buf == "$Elements") {
|
||||
parse_elements(fin);
|
||||
fin >> buf;
|
||||
if (buf != "$EndElements") { throw std::runtime_error("Unexpected tag"); }
|
||||
} else if (buf == "$NodeData") {
|
||||
parse_node_field(fin);
|
||||
fin >> buf;
|
||||
if (buf != "$EndNodeData") { throw std::runtime_error("Unexpected tag"); }
|
||||
} else if (buf == "$ElementData") {
|
||||
parse_element_field(fin);
|
||||
fin >> buf;
|
||||
if (buf != "$EndElementData") { throw std::runtime_error("Unexpected tag"); }
|
||||
} else if (fin.eof()) {
|
||||
break;
|
||||
} else {
|
||||
parse_unknown_field(fin, buf);
|
||||
}
|
||||
}
|
||||
fin.close();
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshLoader::parse_nodes(std::ifstream& fin) {
|
||||
size_t num_nodes;
|
||||
fin >> num_nodes;
|
||||
m_nodes.resize(num_nodes*3);
|
||||
|
||||
if (m_binary) {
|
||||
size_t stride = (4+3*m_data_size);
|
||||
size_t num_bytes = stride * num_nodes;
|
||||
char* data = new char[num_bytes];
|
||||
igl::_msh_eat_white_space(fin);
|
||||
fin.read(data, num_bytes);
|
||||
|
||||
for (size_t i=0; i<num_nodes; i++) {
|
||||
int node_idx;
|
||||
memcpy(&node_idx, data+i*stride, sizeof(int));
|
||||
node_idx-=1;
|
||||
// directly move into vector storage
|
||||
// this works only when m_data_size==sizeof(Float)==sizeof(double)
|
||||
memcpy(&m_nodes[node_idx*3], data+i*stride + 4, m_data_size*3);
|
||||
}
|
||||
delete [] data;
|
||||
} else {
|
||||
int node_idx;
|
||||
for (size_t i=0; i<num_nodes; i++) {
|
||||
fin >> node_idx;
|
||||
node_idx -= 1;
|
||||
// here it's 3D node explicitly
|
||||
fin >> m_nodes[node_idx*3]
|
||||
>> m_nodes[node_idx*3+1]
|
||||
>> m_nodes[node_idx*3+2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshLoader::parse_elements(std::ifstream& fin) {
|
||||
m_elements_tags.resize(2); //hardcoded to have 2 tags
|
||||
size_t num_elements;
|
||||
fin >> num_elements;
|
||||
|
||||
size_t nodes_per_element;
|
||||
|
||||
if (m_binary) {
|
||||
igl::_msh_eat_white_space(fin);
|
||||
int elem_read = 0;
|
||||
while (elem_read < num_elements) {
|
||||
// Parse element header.
|
||||
int elem_type, num_elems, num_tags;
|
||||
fin.read((char*)&elem_type, sizeof(int));
|
||||
fin.read((char*)&num_elems, sizeof(int));
|
||||
fin.read((char*)&num_tags, sizeof(int));
|
||||
nodes_per_element = num_nodes_per_elem_type(elem_type);
|
||||
|
||||
// store node info
|
||||
for (size_t i=0; i<num_elems; i++) {
|
||||
int elem_idx;
|
||||
|
||||
// all elements in the segment share the same elem_type and number of nodes per element
|
||||
m_elements_types.push_back(elem_type);
|
||||
m_elements_lengths.push_back(nodes_per_element);
|
||||
|
||||
fin.read((char*)&elem_idx, sizeof(int));
|
||||
elem_idx -= 1;
|
||||
m_elements_ids.push_back(elem_idx);
|
||||
|
||||
// read first two tags
|
||||
for (size_t j=0; j<num_tags; j++) {
|
||||
int tag;
|
||||
fin.read((char*)&tag, sizeof(int));
|
||||
if(j<2) m_elements_tags[j].push_back(tag);
|
||||
}
|
||||
|
||||
for (size_t j=num_tags; j<2; j++)
|
||||
m_elements_tags[j].push_back(-1); // fill up tags if less then 2
|
||||
|
||||
m_elements_nodes_idx.push_back(m_elements.size());
|
||||
// Element values.
|
||||
for (size_t j=0; j<nodes_per_element; j++) {
|
||||
int idx;
|
||||
fin.read((char*)&idx, sizeof(int));
|
||||
|
||||
m_elements.push_back(idx-1);
|
||||
}
|
||||
}
|
||||
elem_read += num_elems;
|
||||
}
|
||||
} else {
|
||||
for (size_t i=0; i<num_elements; i++) {
|
||||
// Parse per element header
|
||||
int elem_num, elem_type, num_tags;
|
||||
fin >> elem_num >> elem_type >> num_tags;
|
||||
|
||||
// read tags.
|
||||
for (size_t j=0; j<num_tags; j++) {
|
||||
int tag;
|
||||
fin >> tag;
|
||||
if(j<2) m_elements_tags[j].push_back(tag);
|
||||
}
|
||||
for (size_t j=num_tags; j<2; j++)
|
||||
m_elements_tags[j].push_back(-1); // fill up tags if less then 2
|
||||
|
||||
nodes_per_element = num_nodes_per_elem_type(elem_type);
|
||||
m_elements_types.push_back(elem_type);
|
||||
m_elements_lengths.push_back(nodes_per_element);
|
||||
|
||||
elem_num -= 1;
|
||||
m_elements_ids.push_back(elem_num);
|
||||
m_elements_nodes_idx.push_back(m_elements.size());
|
||||
// Parse node idx.
|
||||
for (size_t j=0; j<nodes_per_element; j++) {
|
||||
int idx;
|
||||
fin >> idx;
|
||||
m_elements.push_back(idx-1); // msh index starts from 1.
|
||||
}
|
||||
}
|
||||
}
|
||||
// debug
|
||||
assert(m_elements_types.size() == m_elements_ids.size());
|
||||
assert(m_elements_tags[0].size() == m_elements_ids.size());
|
||||
assert(m_elements_tags[1].size() == m_elements_ids.size());
|
||||
assert(m_elements_lengths.size() == m_elements_ids.size());
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshLoader::parse_node_field( std::ifstream& fin ) {
|
||||
size_t num_string_tags;
|
||||
size_t num_real_tags;
|
||||
size_t num_int_tags;
|
||||
|
||||
fin >> num_string_tags;
|
||||
std::vector<std::string> str_tags(num_string_tags);
|
||||
|
||||
for (size_t i=0; i<num_string_tags; i++) {
|
||||
igl::_msh_eat_white_space(fin);
|
||||
if (fin.peek() == '\"') {
|
||||
// Handle field name between quotes.
|
||||
char buf[128];
|
||||
fin.get(); // remove the quote at the beginning.
|
||||
fin.getline(buf, 128, '\"');
|
||||
str_tags[i] = std::string(buf);
|
||||
} else {
|
||||
fin >> str_tags[i];
|
||||
}
|
||||
}
|
||||
|
||||
fin >> num_real_tags;
|
||||
std::vector<Float> real_tags(num_real_tags);
|
||||
for (size_t i=0; i<num_real_tags; i++)
|
||||
fin >> real_tags[i];
|
||||
|
||||
fin >> num_int_tags;
|
||||
std::vector<int> int_tags(num_int_tags);
|
||||
for (size_t i=0; i<num_int_tags; i++)
|
||||
fin >> int_tags[i];
|
||||
|
||||
if (num_string_tags <= 0 || num_int_tags <= 2) {
|
||||
throw std::runtime_error("Unexpected number of field tags");
|
||||
}
|
||||
std::string fieldname = str_tags[0];
|
||||
int num_components = int_tags[1];
|
||||
int num_entries = int_tags[2];
|
||||
|
||||
std::vector<Float> field( num_entries*num_components );
|
||||
|
||||
if (m_binary) {
|
||||
size_t num_bytes = (num_components * m_data_size + 4) * num_entries;
|
||||
char* data = new char[num_bytes];
|
||||
igl::_msh_eat_white_space(fin);
|
||||
fin.read(data, num_bytes);
|
||||
for (size_t i=0; i<num_entries; i++) {
|
||||
int node_idx;
|
||||
memcpy(&node_idx,&data[i*(4+num_components*m_data_size)],4);
|
||||
|
||||
if(node_idx<1) throw std::runtime_error("Negative or zero index");
|
||||
node_idx -= 1;
|
||||
|
||||
if(node_idx>=num_entries) throw std::runtime_error("Index too big");
|
||||
size_t base_idx = i*(4+num_components*m_data_size) + 4;
|
||||
// TODO: make this work when m_data_size != sizeof(double) ?
|
||||
memcpy(&field[node_idx*num_components], &data[base_idx], num_components*m_data_size);
|
||||
}
|
||||
delete [] data;
|
||||
} else {
|
||||
int node_idx;
|
||||
for (size_t i=0; i<num_entries; i++) {
|
||||
fin >> node_idx;
|
||||
node_idx -= 1;
|
||||
for (size_t j=0; j<num_components; j++) {
|
||||
fin >> field[node_idx*num_components+j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_node_fields_names.push_back(fieldname);
|
||||
m_node_fields.push_back(field);
|
||||
m_node_fields_components.push_back(num_components);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshLoader::parse_element_field(std::ifstream& fin) {
|
||||
size_t num_string_tags;
|
||||
size_t num_real_tags;
|
||||
size_t num_int_tags;
|
||||
|
||||
fin >> num_string_tags;
|
||||
std::vector<std::string> str_tags(num_string_tags);
|
||||
for (size_t i=0; i<num_string_tags; i++) {
|
||||
igl::_msh_eat_white_space(fin);
|
||||
if (fin.peek() == '\"') {
|
||||
// Handle field name between quoates.
|
||||
char buf[128];
|
||||
fin.get(); // remove the quote at the beginning.
|
||||
fin.getline(buf, 128, '\"');
|
||||
str_tags[i] = buf;
|
||||
} else {
|
||||
fin >> str_tags[i];
|
||||
}
|
||||
}
|
||||
|
||||
fin >> num_real_tags;
|
||||
std::vector<Float> real_tags(num_real_tags);
|
||||
for (size_t i=0; i<num_real_tags; i++)
|
||||
fin >> real_tags[i];
|
||||
|
||||
fin >> num_int_tags;
|
||||
std::vector<int> int_tags(num_int_tags);
|
||||
for (size_t i=0; i<num_int_tags; i++)
|
||||
fin >> int_tags[i];
|
||||
|
||||
if (num_string_tags <= 0 || num_int_tags <= 2) {
|
||||
throw std::runtime_error("Invalid file format");
|
||||
}
|
||||
std::string fieldname = str_tags[0];
|
||||
int num_components = int_tags[1];
|
||||
int num_entries = int_tags[2];
|
||||
std::vector<Float> field(num_entries*num_components);
|
||||
|
||||
if (m_binary) {
|
||||
size_t num_bytes = (num_components * m_data_size + 4) * num_entries;
|
||||
char* data = new char[num_bytes];
|
||||
igl::_msh_eat_white_space(fin);
|
||||
fin.read(data, num_bytes);
|
||||
for (int i=0; i<num_entries; i++) {
|
||||
int elem_idx;
|
||||
// works with sizeof(int)==4
|
||||
memcpy(&elem_idx, &data[i*(4+num_components*m_data_size)],4);
|
||||
elem_idx -= 1;
|
||||
|
||||
// directly copy data into vector storage space
|
||||
memcpy(&field[elem_idx*num_components], &data[i*(4+num_components*m_data_size) + 4], m_data_size*num_components);
|
||||
}
|
||||
delete [] data;
|
||||
} else {
|
||||
int elem_idx;
|
||||
for (size_t i=0; i<num_entries; i++) {
|
||||
fin >> elem_idx;
|
||||
elem_idx -= 1;
|
||||
for (size_t j=0; j<num_components; j++) {
|
||||
fin >> field[elem_idx*num_components+j];
|
||||
}
|
||||
}
|
||||
}
|
||||
m_element_fields_names.push_back(fieldname);
|
||||
m_element_fields.push_back(field);
|
||||
m_element_fields_components.push_back(num_components);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshLoader::parse_unknown_field(std::ifstream& fin,
|
||||
const std::string& fieldname) {
|
||||
std::cerr << "Warning: \"" << fieldname << "\" not supported yet. Ignored." << std::endl;
|
||||
std::string endmark = fieldname.substr(0,1) + "End"
|
||||
+ fieldname.substr(1,fieldname.size()-1);
|
||||
|
||||
std::string buf("");
|
||||
while (buf != endmark && !fin.eof()) {
|
||||
fin >> buf;
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE int igl::MshLoader::num_nodes_per_elem_type(int elem_type) {
|
||||
int nodes_per_element = 0;
|
||||
switch (elem_type) {
|
||||
case ELEMENT_LINE: // 2-node line
|
||||
nodes_per_element = 2;
|
||||
break;
|
||||
case ELEMENT_TRI:
|
||||
nodes_per_element = 3; // 3-node triangle
|
||||
break;
|
||||
case ELEMENT_QUAD:
|
||||
nodes_per_element = 4; // 5-node quad
|
||||
break;
|
||||
case ELEMENT_TET:
|
||||
nodes_per_element = 4; // 4-node tetrahedra
|
||||
break;
|
||||
case ELEMENT_HEX: // 8-node hexahedron
|
||||
nodes_per_element = 8;
|
||||
break;
|
||||
case ELEMENT_PRISM: // 6-node prism
|
||||
nodes_per_element = 6;
|
||||
break;
|
||||
case ELEMENT_LINE_2ND_ORDER:
|
||||
nodes_per_element = 3;
|
||||
break;
|
||||
case ELEMENT_TRI_2ND_ORDER:
|
||||
nodes_per_element = 6;
|
||||
break;
|
||||
case ELEMENT_QUAD_2ND_ORDER:
|
||||
nodes_per_element = 9;
|
||||
break;
|
||||
case ELEMENT_TET_2ND_ORDER:
|
||||
nodes_per_element = 10;
|
||||
break;
|
||||
case ELEMENT_HEX_2ND_ORDER:
|
||||
nodes_per_element = 27;
|
||||
break;
|
||||
case ELEMENT_PRISM_2ND_ORDER:
|
||||
nodes_per_element = 18;
|
||||
break;
|
||||
case ELEMENT_PYRAMID_2ND_ORDER:
|
||||
nodes_per_element = 14;
|
||||
break;
|
||||
case ELEMENT_POINT: // 1-node point
|
||||
nodes_per_element = 1;
|
||||
break;
|
||||
default:
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Element type (" << elem_type << ") is not supported yet."
|
||||
<< std::endl;
|
||||
throw std::runtime_error(err_msg.str());
|
||||
}
|
||||
return nodes_per_element;
|
||||
}
|
||||
|
||||
|
||||
IGL_INLINE bool igl::MshLoader::is_element_map_identity() const
|
||||
{
|
||||
for(int i=0;i<m_elements_ids.size();i++) {
|
||||
int id=m_elements_ids[i];
|
||||
if (id!=i) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
IGL_INLINE void igl::MshLoader::index_structures(int tag_column)
|
||||
{
|
||||
//cleanup
|
||||
m_structure_index.clear();
|
||||
m_structures.clear();
|
||||
m_structure_length.clear();
|
||||
|
||||
//index structure tags
|
||||
for(auto i=0; i != m_elements_tags[tag_column].size(); ++i )
|
||||
{
|
||||
m_structure_index.insert(
|
||||
std::pair<msh_struct,int>(
|
||||
msh_struct( m_elements_tags[tag_column][i],
|
||||
m_elements_types[i]), i)
|
||||
);
|
||||
}
|
||||
|
||||
// identify unique structures
|
||||
std::vector<StructIndex::value_type> _unique_structs;
|
||||
std::unique_copy(std::begin(m_structure_index),
|
||||
std::end(m_structure_index),
|
||||
std::back_inserter(_unique_structs),
|
||||
[](const StructIndex::value_type &c1, const StructIndex::value_type &c2)
|
||||
{ return c1.first == c2.first; });
|
||||
|
||||
std::for_each( _unique_structs.begin(), _unique_structs.end(),
|
||||
[this](const StructIndex::value_type &n){ this->m_structures.push_back(n.first); });
|
||||
|
||||
for(auto t = m_structures.begin(); t != m_structures.end(); ++t)
|
||||
{
|
||||
// identify all elements corresponding to this tag
|
||||
auto structure_range = m_structure_index.equal_range( *t );
|
||||
int cnt=0;
|
||||
|
||||
for(auto i=structure_range.first; i!=structure_range.second; i++)
|
||||
cnt++;
|
||||
|
||||
m_structure_length.insert( std::pair<msh_struct,int>( *t, cnt));
|
||||
}
|
||||
}
|
||||
@@ -1,347 +0,0 @@
|
||||
// based on MSH writer from PyMesh
|
||||
|
||||
// Copyright (c) 2015 Qingnan Zhou <qzhou@adobe.com>
|
||||
// Copyright (C) 2020 Vladimir Fonov <vladimir.fonov@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 "MshSaver.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <exception>
|
||||
|
||||
|
||||
IGL_INLINE igl::MshSaver::MshSaver(const std::string& filename, bool binary) :
|
||||
m_binary(binary), m_num_nodes(0), m_num_elements(0) {
|
||||
if (!m_binary) {
|
||||
fout.open(filename.c_str(), std::fstream::out);
|
||||
} else {
|
||||
fout.open(filename.c_str(), std::fstream::binary);
|
||||
}
|
||||
if (!fout) {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Error opening " << filename << " to write msh file." << std::endl;
|
||||
throw std::ios_base::failure(err_msg.str());
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE igl::MshSaver::~MshSaver() {
|
||||
fout.close();
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshSaver::save_mesh(
|
||||
const FloatVector& nodes,
|
||||
const IndexVector& elements,
|
||||
const IntVector& element_lengths,
|
||||
const IntVector& element_types,
|
||||
const IntVector& element_tags
|
||||
) {
|
||||
|
||||
save_header();
|
||||
|
||||
save_nodes(nodes);
|
||||
|
||||
save_elements(elements, element_lengths, element_types, element_tags );
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshSaver::save_header() {
|
||||
if (!m_binary) {
|
||||
fout << "$MeshFormat" << std::endl;
|
||||
fout << "2.2 0 " << sizeof(double) << std::endl;
|
||||
fout << "$EndMeshFormat" << std::endl;
|
||||
fout.precision(17);
|
||||
} else {
|
||||
fout << "$MeshFormat" << std::endl;
|
||||
fout << "2.2 1 " << sizeof(double) << std::endl;
|
||||
int one = 1;
|
||||
fout.write((char*)&one, sizeof(int));
|
||||
fout << "\n$EndMeshFormat" << std::endl;
|
||||
}
|
||||
fout.flush();
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshSaver::save_nodes(const FloatVector& nodes) {
|
||||
// Save nodes.
|
||||
// 3D hadrcoded
|
||||
m_num_nodes = nodes.size() / 3;
|
||||
fout << "$Nodes" << std::endl;
|
||||
fout << m_num_nodes << std::endl;
|
||||
if (!m_binary) {
|
||||
for (size_t i=0; i<nodes.size(); i+=3) {
|
||||
//const VectorF& v = nodes.segment(i,m_dim);
|
||||
int node_idx = i/3 + 1;
|
||||
fout << node_idx << " " << nodes[i] << " " << nodes[i+1] << " " << nodes[i+2] << std::endl;
|
||||
}
|
||||
} else {
|
||||
for (size_t i=0; i<nodes.size(); i+=3) {
|
||||
//const VectorF& v = nodes.segment(i,m_dim);
|
||||
int node_idx = i/3 + 1;
|
||||
fout.write((const char*)&node_idx, sizeof(int));
|
||||
fout.write((const char*)&nodes[i], sizeof(Float)*3);
|
||||
}
|
||||
}
|
||||
fout << "$EndNodes" << std::endl;
|
||||
fout.flush();
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshSaver::save_elements(const IndexVector& elements,
|
||||
const IntVector& element_lengths,
|
||||
const IntVector& element_types,
|
||||
const IntVector& element_tags)
|
||||
{
|
||||
|
||||
m_num_elements = element_tags.size();
|
||||
assert(element_lengths.size() == element_types.size() );
|
||||
assert(element_lengths.size() == element_tags.size() );
|
||||
// TODO: sum up all lengths
|
||||
// Save elements.
|
||||
// node inxes are 1-based
|
||||
fout << "$Elements" << std::endl;
|
||||
fout << m_num_elements << std::endl;
|
||||
|
||||
if (m_num_elements > 0) {
|
||||
//int elem_type = el_type;
|
||||
int num_elems = m_num_elements;
|
||||
//int tags = 0;
|
||||
if (!m_binary) {
|
||||
size_t el_ptr=0;
|
||||
for (size_t i=0;i<m_num_elements;++i) {
|
||||
|
||||
int elem_num = (int) i + 1;
|
||||
///VectorI elem = elements.segment(i, nodes_per_element) + VectorI::Ones(nodes_per_element);
|
||||
// hardcoded: duplicate tags (I don't know why)
|
||||
fout << elem_num << " " << element_types[i] << " " << 2 << " "<< element_tags[i] << " "<< element_tags[i] << " ";
|
||||
for (size_t j=0; j<element_lengths[i]; j++) {
|
||||
fout << elements[el_ptr + j] + 1 << " ";
|
||||
}
|
||||
fout << std::endl;
|
||||
el_ptr+=element_lengths[i];
|
||||
}
|
||||
} else {
|
||||
size_t el_ptr=0,i=0;
|
||||
while(i<m_num_elements) {
|
||||
|
||||
// write elements in consistent chunks
|
||||
// TODO: refactor this code to be able to specify different elements
|
||||
// more effeciently
|
||||
|
||||
int elem_type=-1;
|
||||
int elem_len=-1;
|
||||
size_t j=i;
|
||||
for(;j<m_num_elements;++j)
|
||||
{
|
||||
if( elem_type==-1 )
|
||||
{
|
||||
elem_type=element_types[j];
|
||||
elem_len=element_lengths[j];
|
||||
} else if( elem_type!=element_types[j] ||
|
||||
elem_len!=element_lengths[j]) {
|
||||
break; // found the edge of the segment
|
||||
}
|
||||
}
|
||||
|
||||
//hardcoded: 2 tags
|
||||
int num_elems=j-i, num_tags=2;
|
||||
|
||||
fout.write((const char*)& elem_type, sizeof(int));
|
||||
fout.write((const char*)& num_elems, sizeof(int));
|
||||
fout.write((const char*)& num_tags, sizeof(int));
|
||||
|
||||
for(int k=0;k<num_elems; ++k,++i){
|
||||
int elem_num = (int )i + 1;
|
||||
fout.write((const char*)&elem_num, sizeof(int));
|
||||
|
||||
// HACK: hardcoded 2 tags
|
||||
fout.write((const char*)& element_tags[i], sizeof(int));
|
||||
fout.write((const char*)& element_tags[i], sizeof(int));
|
||||
|
||||
for (size_t e=0; e<elem_len; e++) {
|
||||
int _elem = static_cast<int>( elements[el_ptr + e] )+1;
|
||||
fout.write((const char*)&_elem, sizeof(int));
|
||||
}
|
||||
el_ptr+=elem_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fout << "$EndElements" << std::endl;
|
||||
fout.flush();
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshSaver::save_scalar_field(const std::string& fieldname, const FloatVector& field) {
|
||||
assert(field.size() == m_num_nodes);
|
||||
fout << "$NodeData" << std::endl;
|
||||
fout << "1" << std::endl; // num string tags.
|
||||
fout << "\"" << fieldname << "\"" << std::endl;
|
||||
fout << "1" << std::endl; // num real tags.
|
||||
fout << "0.0" << std::endl; // time value.
|
||||
fout << "3" << std::endl; // num int tags.
|
||||
fout << "0" << std::endl; // the time step
|
||||
fout << "1" << std::endl; // 1-component scalar field.
|
||||
fout << m_num_nodes << std::endl; // number of nodes
|
||||
|
||||
if (m_binary) {
|
||||
for (size_t i=0; i<m_num_nodes; i++) {
|
||||
int node_idx = i+1;
|
||||
fout.write((char*)&node_idx, sizeof(int));
|
||||
fout.write((char*)&field[i], sizeof(Float));
|
||||
}
|
||||
} else {
|
||||
for (size_t i=0; i<m_num_nodes; i++) {
|
||||
int node_idx = i+1;
|
||||
fout << node_idx << " " << field[i] << std::endl;
|
||||
}
|
||||
}
|
||||
fout << "$EndNodeData" << std::endl;
|
||||
fout.flush();
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshSaver::save_vector_field(const std::string& fieldname, const FloatVector& field) {
|
||||
assert(field.size() == 3 * m_num_nodes);
|
||||
|
||||
fout << "$NodeData" << std::endl;
|
||||
fout << "1" << std::endl; // num string tags.
|
||||
fout << "\"" << fieldname << "\"" << std::endl;
|
||||
fout << "1" << std::endl; // num real tags.
|
||||
fout << "0.0" << std::endl; // time value.
|
||||
fout << "3" << std::endl; // num int tags.
|
||||
fout << "0" << std::endl; // the time step
|
||||
fout << "3" << std::endl; // 3-component vector field.
|
||||
fout << m_num_nodes << std::endl; // number of nodes
|
||||
|
||||
const Float zero = 0.0;
|
||||
if (m_binary) {
|
||||
for (size_t i=0; i<m_num_nodes; i++) {
|
||||
int node_idx = i+1;
|
||||
fout.write((const char*)&node_idx, sizeof(int));
|
||||
fout.write((const char*)&field[i*3], sizeof(Float)*3);
|
||||
}
|
||||
} else {
|
||||
for (size_t i=0; i<m_num_nodes; i++) {
|
||||
int node_idx = i+1;
|
||||
fout << node_idx
|
||||
<< " " << field[i*3]
|
||||
<< " " << field[i*3+1]
|
||||
<< " " << field[i*3+2]
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
fout << "$EndNodeData" << std::endl;
|
||||
fout.flush();
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshSaver::save_elem_scalar_field(const std::string& fieldname, const FloatVector& field) {
|
||||
assert(field.size() == m_num_elements);
|
||||
fout << "$ElementData" << std::endl;
|
||||
fout << 1 << std::endl; // num string tags.
|
||||
fout << "\"" << fieldname << "\"" << std::endl;
|
||||
fout << "1" << std::endl; // num real tags.
|
||||
fout << "0.0" << std::endl; // time value.
|
||||
fout << "3" << std::endl; // num int tags.
|
||||
fout << "0" << std::endl; // the time step
|
||||
fout << "1" << std::endl; // 1-component scalar field.
|
||||
fout << m_num_elements << std::endl; // number of elements
|
||||
|
||||
if (m_binary) {
|
||||
for (size_t i=0; i<m_num_elements; i++) {
|
||||
int elem_idx = i+1;
|
||||
fout.write((const char*)&elem_idx, sizeof(int));
|
||||
fout.write((const char*)&field[i], sizeof(Float));
|
||||
}
|
||||
} else {
|
||||
for (size_t i=0; i<m_num_elements; i++) {
|
||||
int elem_idx = i+1;
|
||||
fout << elem_idx << " " << field[i] << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
fout << "$EndElementData" << std::endl;
|
||||
fout.flush();
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::MshSaver::save_elem_vector_field(const std::string& fieldname, const FloatVector& field) {
|
||||
assert(field.size() == m_num_elements * 3);
|
||||
fout << "$ElementData" << std::endl;
|
||||
fout << 1 << std::endl; // num string tags.
|
||||
fout << "\"" << fieldname << "\"" << std::endl;
|
||||
fout << "1" << std::endl; // num real tags.
|
||||
fout << "0.0" << std::endl; // time value.
|
||||
fout << "3" << std::endl; // num int tags.
|
||||
fout << "0" << std::endl; // the time step
|
||||
fout << "3" << std::endl; // 3-component vector field.
|
||||
fout << m_num_elements << std::endl; // number of elements
|
||||
|
||||
const Float zero = 0.0;
|
||||
if (m_binary) {
|
||||
for (size_t i=0; i<m_num_elements; ++i) {
|
||||
int elem_idx = i+1;
|
||||
fout.write((const char*)&elem_idx, sizeof(int));
|
||||
fout.write((const char*)&field[i*3], sizeof(Float) * 3);
|
||||
}
|
||||
} else {
|
||||
for (size_t i=0; i<m_num_elements; ++i) {
|
||||
int elem_idx = i+1;
|
||||
fout << elem_idx
|
||||
<< " " << field[i*3]
|
||||
<< " " << field[i*3+1]
|
||||
<< " " << field[i*3+2]
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
fout << "$EndElementData" << std::endl;
|
||||
fout.flush();
|
||||
}
|
||||
|
||||
|
||||
IGL_INLINE void igl::MshSaver::save_elem_tensor_field(const std::string& fieldname, const FloatVector& field) {
|
||||
assert(field.size() == m_num_elements * 3 * (3 + 1) / 2);
|
||||
fout << "$ElementData" << std::endl;
|
||||
fout << 1 << std::endl; // num string tags.
|
||||
fout << "\"" << fieldname << "\"" << std::endl;
|
||||
fout << "1" << std::endl; // num real tags.
|
||||
fout << "0.0" << std::endl; // time value.
|
||||
fout << "3" << std::endl; // num int tags.
|
||||
fout << "0" << std::endl; // the time step
|
||||
fout << "9" << std::endl; // 9-component tensor field.
|
||||
fout << m_num_elements << std::endl; // number of elements
|
||||
|
||||
const Float zero = 0.0;
|
||||
|
||||
if (m_binary) {
|
||||
for (size_t i=0; i<m_num_elements; i++) {
|
||||
int elem_idx = i+1;
|
||||
fout.write((char*)&elem_idx, sizeof(int));
|
||||
//const VectorF& val = field.segment(i*6, 6);
|
||||
const Float* val = &field[i*6];
|
||||
Float tensor[9] = {
|
||||
val[0], val[5], val[4],
|
||||
val[5], val[1], val[3],
|
||||
val[4], val[3], val[2] };
|
||||
fout.write((char*)tensor, sizeof(Float) * 9);
|
||||
}
|
||||
} else {
|
||||
for (size_t i=0; i<m_num_elements; i++) {
|
||||
int elem_idx = i+1;
|
||||
const Float* val = &field[i*6];
|
||||
fout << elem_idx
|
||||
<< " " << val[0]
|
||||
<< " " << val[5]
|
||||
<< " " << val[4]
|
||||
<< " " << val[5]
|
||||
<< " " << val[1]
|
||||
<< " " << val[3]
|
||||
<< " " << val[4]
|
||||
<< " " << val[3]
|
||||
<< " " << val[2]
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
fout << "$EndElementData" << std::endl;
|
||||
fout.flush();
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2018 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 "accumarray.h"
|
||||
#include <cassert>
|
||||
|
||||
template <
|
||||
typename DerivedS,
|
||||
typename DerivedV,
|
||||
typename DerivedA
|
||||
>
|
||||
void igl::accumarray(
|
||||
const Eigen::MatrixBase<DerivedS> & S,
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::PlainObjectBase<DerivedA> & A)
|
||||
{
|
||||
assert(V.size() == S.size() && "S and V should be same size");
|
||||
if(S.size() == 0) { A.resize(0,1); return; }
|
||||
A.setZero(S.maxCoeff()+1,1);
|
||||
for(int s = 0;s<S.size();s++)
|
||||
{
|
||||
A(S(s)) += V(s);
|
||||
}
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedS,
|
||||
typename DerivedA
|
||||
>
|
||||
void igl::accumarray(
|
||||
const Eigen::MatrixBase<DerivedS> & S,
|
||||
const typename DerivedA::Scalar V,
|
||||
Eigen::PlainObjectBase<DerivedA> & A)
|
||||
{
|
||||
if(S.size() == 0) { A.resize(0,1); return; }
|
||||
A.setZero(S.maxCoeff()+1,1);
|
||||
for(int s = 0;s<S.size();s++)
|
||||
{
|
||||
A(S(s)) += V;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::accumarray<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::accumarray<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
@@ -1,370 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "active_set.h"
|
||||
#include "min_quad_with_fixed.h"
|
||||
#include "slice.h"
|
||||
#include "slice_into.h"
|
||||
#include "cat.h"
|
||||
//#include "matlab_format.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
|
||||
template <
|
||||
typename AT,
|
||||
typename DerivedB,
|
||||
typename Derivedknown,
|
||||
typename DerivedY,
|
||||
typename AeqT,
|
||||
typename DerivedBeq,
|
||||
typename AieqT,
|
||||
typename DerivedBieq,
|
||||
typename Derivedlx,
|
||||
typename Derivedux,
|
||||
typename DerivedZ
|
||||
>
|
||||
IGL_INLINE igl::SolverStatus igl::active_set(
|
||||
const Eigen::SparseMatrix<AT>& A,
|
||||
const Eigen::PlainObjectBase<DerivedB> & B,
|
||||
const Eigen::PlainObjectBase<Derivedknown> & known,
|
||||
const Eigen::PlainObjectBase<DerivedY> & Y,
|
||||
const Eigen::SparseMatrix<AeqT>& Aeq,
|
||||
const Eigen::PlainObjectBase<DerivedBeq> & Beq,
|
||||
const Eigen::SparseMatrix<AieqT>& Aieq,
|
||||
const Eigen::PlainObjectBase<DerivedBieq> & Bieq,
|
||||
const Eigen::PlainObjectBase<Derivedlx> & p_lx,
|
||||
const Eigen::PlainObjectBase<Derivedux> & p_ux,
|
||||
const igl::active_set_params & params,
|
||||
Eigen::PlainObjectBase<DerivedZ> & Z
|
||||
)
|
||||
{
|
||||
//#define ACTIVE_SET_CPP_DEBUG
|
||||
#if defined(ACTIVE_SET_CPP_DEBUG) && !defined(_MSC_VER)
|
||||
# warning "ACTIVE_SET_CPP_DEBUG"
|
||||
#endif
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
SolverStatus ret = SOLVER_STATUS_ERROR;
|
||||
const int n = A.rows();
|
||||
assert(n == A.cols() && "A must be square");
|
||||
// Discard const qualifiers
|
||||
//if(B.size() == 0)
|
||||
//{
|
||||
// B = DerivedB::Zero(n,1);
|
||||
//}
|
||||
assert(n == B.rows() && "B.rows() must match A.rows()");
|
||||
assert(B.cols() == 1 && "B must be a column vector");
|
||||
assert(Y.cols() == 1 && "Y must be a column vector");
|
||||
assert((Aeq.size() == 0 && Beq.size() == 0) || Aeq.cols() == n);
|
||||
assert((Aeq.size() == 0 && Beq.size() == 0) || Aeq.rows() == Beq.rows());
|
||||
assert((Aeq.size() == 0 && Beq.size() == 0) || Beq.cols() == 1);
|
||||
assert((Aieq.size() == 0 && Bieq.size() == 0) || Aieq.cols() == n);
|
||||
assert((Aieq.size() == 0 && Bieq.size() == 0) || Aieq.rows() == Bieq.rows());
|
||||
assert((Aieq.size() == 0 && Bieq.size() == 0) || Bieq.cols() == 1);
|
||||
Eigen::Matrix<typename Derivedlx::Scalar,Eigen::Dynamic,1> lx;
|
||||
Eigen::Matrix<typename Derivedux::Scalar,Eigen::Dynamic,1> ux;
|
||||
if(p_lx.size() == 0)
|
||||
{
|
||||
lx = Derivedlx::Constant(
|
||||
n,1,-numeric_limits<typename Derivedlx::Scalar>::max());
|
||||
}else
|
||||
{
|
||||
lx = p_lx;
|
||||
}
|
||||
if(p_ux.size() == 0)
|
||||
{
|
||||
ux = Derivedux::Constant(
|
||||
n,1,numeric_limits<typename Derivedux::Scalar>::max());
|
||||
}else
|
||||
{
|
||||
ux = p_ux;
|
||||
}
|
||||
assert(lx.rows() == n && "lx must have n rows");
|
||||
assert(ux.rows() == n && "ux must have n rows");
|
||||
assert(ux.cols() == 1 && "lx must be a column vector");
|
||||
assert(lx.cols() == 1 && "ux must be a column vector");
|
||||
assert((ux.array()-lx.array()).minCoeff() > 0 && "ux(i) must be > lx(i)");
|
||||
if(Z.size() != 0)
|
||||
{
|
||||
// Initial guess should have correct size
|
||||
assert(Z.rows() == n && "Z must have n rows");
|
||||
assert(Z.cols() == 1 && "Z must be a column vector");
|
||||
}
|
||||
assert(known.cols() == 1 && "known must be a column vector");
|
||||
// Number of knowns
|
||||
const int nk = known.size();
|
||||
|
||||
// Initialize active sets
|
||||
typedef int BOOL;
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
Matrix<BOOL,Dynamic,1> as_lx = Matrix<BOOL,Dynamic,1>::Constant(n,1,FALSE);
|
||||
Matrix<BOOL,Dynamic,1> as_ux = Matrix<BOOL,Dynamic,1>::Constant(n,1,FALSE);
|
||||
Matrix<BOOL,Dynamic,1> as_ieq = Matrix<BOOL,Dynamic,1>::Constant(Aieq.rows(),1,FALSE);
|
||||
|
||||
// Keep track of previous Z for comparison
|
||||
DerivedZ old_Z;
|
||||
old_Z = DerivedZ::Constant(
|
||||
n,1,numeric_limits<typename DerivedZ::Scalar>::max());
|
||||
|
||||
int iter = 0;
|
||||
while(true)
|
||||
{
|
||||
#ifdef ACTIVE_SET_CPP_DEBUG
|
||||
cout<<"Iteration: "<<iter<<":"<<endl;
|
||||
cout<<" pre"<<endl;
|
||||
#endif
|
||||
// FIND BREACHES OF CONSTRAINTS
|
||||
int new_as_lx = 0;
|
||||
int new_as_ux = 0;
|
||||
int new_as_ieq = 0;
|
||||
if(Z.size() > 0)
|
||||
{
|
||||
for(int z = 0;z < n;z++)
|
||||
{
|
||||
if(Z(z) < lx(z))
|
||||
{
|
||||
new_as_lx += (as_lx(z)?0:1);
|
||||
//new_as_lx++;
|
||||
as_lx(z) = TRUE;
|
||||
}
|
||||
if(Z(z) > ux(z))
|
||||
{
|
||||
new_as_ux += (as_ux(z)?0:1);
|
||||
//new_as_ux++;
|
||||
as_ux(z) = TRUE;
|
||||
}
|
||||
}
|
||||
if(Aieq.rows() > 0)
|
||||
{
|
||||
DerivedZ AieqZ;
|
||||
AieqZ = Aieq*Z;
|
||||
for(int a = 0;a<Aieq.rows();a++)
|
||||
{
|
||||
if(AieqZ(a) > Bieq(a))
|
||||
{
|
||||
new_as_ieq += (as_ieq(a)?0:1);
|
||||
as_ieq(a) = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef ACTIVE_SET_CPP_DEBUG
|
||||
cout<<" new_as_lx: "<<new_as_lx<<endl;
|
||||
cout<<" new_as_ux: "<<new_as_ux<<endl;
|
||||
#endif
|
||||
const double diff = (Z-old_Z).squaredNorm();
|
||||
#ifdef ACTIVE_SET_CPP_DEBUG
|
||||
cout<<"diff: "<<diff<<endl;
|
||||
#endif
|
||||
if(diff < params.solution_diff_threshold)
|
||||
{
|
||||
ret = SOLVER_STATUS_CONVERGED;
|
||||
break;
|
||||
}
|
||||
old_Z = Z;
|
||||
}
|
||||
|
||||
const int as_lx_count = std::count(as_lx.data(),as_lx.data()+n,TRUE);
|
||||
const int as_ux_count = std::count(as_ux.data(),as_ux.data()+n,TRUE);
|
||||
const int as_ieq_count =
|
||||
std::count(as_ieq.data(),as_ieq.data()+as_ieq.size(),TRUE);
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
int count = 0;
|
||||
for(int a = 0;a<as_ieq.size();a++)
|
||||
{
|
||||
if(as_ieq(a))
|
||||
{
|
||||
assert(as_ieq(a) == TRUE);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
assert(as_ieq_count == count);
|
||||
}
|
||||
#endif
|
||||
|
||||
// PREPARE FIXED VALUES
|
||||
Derivedknown known_i;
|
||||
known_i.resize(nk + as_lx_count + as_ux_count,1);
|
||||
DerivedY Y_i;
|
||||
Y_i.resize(nk + as_lx_count + as_ux_count,1);
|
||||
{
|
||||
known_i.block(0,0,known.rows(),known.cols()) = known;
|
||||
Y_i.block(0,0,Y.rows(),Y.cols()) = Y;
|
||||
int k = nk;
|
||||
// Then all lx
|
||||
for(int z = 0;z < n;z++)
|
||||
{
|
||||
if(as_lx(z))
|
||||
{
|
||||
known_i(k) = z;
|
||||
Y_i(k) = lx(z);
|
||||
k++;
|
||||
}
|
||||
}
|
||||
// Finally all ux
|
||||
for(int z = 0;z < n;z++)
|
||||
{
|
||||
if(as_ux(z))
|
||||
{
|
||||
known_i(k) = z;
|
||||
Y_i(k) = ux(z);
|
||||
k++;
|
||||
}
|
||||
}
|
||||
assert(k==Y_i.size());
|
||||
assert(k==known_i.size());
|
||||
}
|
||||
//cout<<matlab_format((known_i.array()+1).eval(),"known_i")<<endl;
|
||||
// PREPARE EQUALITY CONSTRAINTS
|
||||
Eigen::Matrix<typename DerivedY::Scalar, Eigen::Dynamic, 1> as_ieq_list(as_ieq_count,1);
|
||||
// Gather active constraints and resp. rhss
|
||||
DerivedBeq Beq_i;
|
||||
Beq_i.resize(Beq.rows()+as_ieq_count,1);
|
||||
Beq_i.head(Beq.rows()) = Beq;
|
||||
{
|
||||
int k =0;
|
||||
for(int a=0;a<as_ieq.size();a++)
|
||||
{
|
||||
if(as_ieq(a))
|
||||
{
|
||||
assert(k<as_ieq_list.size());
|
||||
as_ieq_list(k)=a;
|
||||
Beq_i(Beq.rows()+k,0) = Bieq(k,0);
|
||||
k++;
|
||||
}
|
||||
}
|
||||
assert(k == as_ieq_count);
|
||||
}
|
||||
// extract active constraint rows
|
||||
SparseMatrix<AeqT> Aeq_i,Aieq_i;
|
||||
slice(Aieq,as_ieq_list,1,Aieq_i);
|
||||
// Append to equality constraints
|
||||
cat(1,Aeq,Aieq_i,Aeq_i);
|
||||
|
||||
|
||||
min_quad_with_fixed_data<AT> data;
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
// NO DUPES!
|
||||
Matrix<BOOL,Dynamic,1> fixed = Matrix<BOOL,Dynamic,1>::Constant(n,1,FALSE);
|
||||
for(int k = 0;k<known_i.size();k++)
|
||||
{
|
||||
assert(!fixed[known_i(k)]);
|
||||
fixed[known_i(k)] = TRUE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
DerivedZ sol;
|
||||
if(known_i.size() == A.rows())
|
||||
{
|
||||
// Everything's fixed?
|
||||
#ifdef ACTIVE_SET_CPP_DEBUG
|
||||
cout<<" everything's fixed."<<endl;
|
||||
#endif
|
||||
Z.resize(A.rows(),Y_i.cols());
|
||||
slice_into(Y_i,known_i,1,Z);
|
||||
sol.resize(0,Y_i.cols());
|
||||
assert(Aeq_i.rows() == 0 && "All fixed but linearly constrained");
|
||||
}else
|
||||
{
|
||||
#ifdef ACTIVE_SET_CPP_DEBUG
|
||||
cout<<" min_quad_with_fixed_precompute"<<endl;
|
||||
#endif
|
||||
if(!min_quad_with_fixed_precompute(A,known_i,Aeq_i,params.Auu_pd,data))
|
||||
{
|
||||
cerr<<"Error: min_quad_with_fixed precomputation failed."<<endl;
|
||||
if(iter > 0 && Aeq_i.rows() > Aeq.rows())
|
||||
{
|
||||
cerr<<" *Are you sure rows of [Aeq;Aieq] are linearly independent?*"<<
|
||||
endl;
|
||||
}
|
||||
ret = SOLVER_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
#ifdef ACTIVE_SET_CPP_DEBUG
|
||||
cout<<" min_quad_with_fixed_solve"<<endl;
|
||||
#endif
|
||||
if(!min_quad_with_fixed_solve(data,B,Y_i,Beq_i,Z,sol))
|
||||
{
|
||||
cerr<<"Error: min_quad_with_fixed solve failed."<<endl;
|
||||
ret = SOLVER_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
//cout<<matlab_format((Aeq*Z-Beq).eval(),"cr")<<endl;
|
||||
//cout<<matlab_format(Z,"Z")<<endl;
|
||||
#ifdef ACTIVE_SET_CPP_DEBUG
|
||||
cout<<" post"<<endl;
|
||||
#endif
|
||||
// Computing Lagrange multipliers needs to be adjusted slightly if A is not symmetric
|
||||
assert(data.Auu_sym);
|
||||
}
|
||||
|
||||
// Compute Lagrange multiplier values for known_i
|
||||
SparseMatrix<AT> Ak;
|
||||
// Slow
|
||||
slice(A,known_i,1,Ak);
|
||||
DerivedB Bk;
|
||||
slice(B,known_i,Bk);
|
||||
MatrixXd Lambda_known_i = -(0.5*Ak*Z + 0.5*Bk);
|
||||
// reverse the lambda values for lx
|
||||
Lambda_known_i.block(nk,0,as_lx_count,1) =
|
||||
(-1*Lambda_known_i.block(nk,0,as_lx_count,1)).eval();
|
||||
|
||||
// Extract Lagrange multipliers for Aieq_i (always at back of sol)
|
||||
VectorXd Lambda_Aieq_i(Aieq_i.rows(),1);
|
||||
for(int l = 0;l<Aieq_i.rows();l++)
|
||||
{
|
||||
Lambda_Aieq_i(Aieq_i.rows()-1-l) = sol(sol.rows()-1-l);
|
||||
}
|
||||
|
||||
// Remove from active set
|
||||
for(int l = 0;l<as_lx_count;l++)
|
||||
{
|
||||
if(Lambda_known_i(nk + l) < params.inactive_threshold)
|
||||
{
|
||||
as_lx(known_i(nk + l)) = FALSE;
|
||||
}
|
||||
}
|
||||
for(int u = 0;u<as_ux_count;u++)
|
||||
{
|
||||
if(Lambda_known_i(nk + as_lx_count + u) <
|
||||
params.inactive_threshold)
|
||||
{
|
||||
as_ux(known_i(nk + as_lx_count + u)) = FALSE;
|
||||
}
|
||||
}
|
||||
for(int a = 0;a<as_ieq_count;a++)
|
||||
{
|
||||
if(Lambda_Aieq_i(a) < params.inactive_threshold)
|
||||
{
|
||||
as_ieq(int(as_ieq_list(a))) = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
iter++;
|
||||
//cout<<iter<<endl;
|
||||
if(params.max_iter>0 && iter>=params.max_iter)
|
||||
{
|
||||
ret = SOLVER_STATUS_MAX_ITER;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template igl::SolverStatus igl::active_set<double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, igl::active_set_params const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
|
||||
template igl::SolverStatus igl::active_set<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, igl::active_set_params const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -1,180 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "adjacency_list.h"
|
||||
|
||||
#include "verbose.h"
|
||||
#include <algorithm>
|
||||
|
||||
template <typename Index, typename IndexVector>
|
||||
IGL_INLINE void igl::adjacency_list(
|
||||
const Eigen::MatrixBase<Index> & F,
|
||||
std::vector<std::vector<IndexVector> >& A,
|
||||
bool sorted)
|
||||
{
|
||||
A.clear();
|
||||
A.resize(F.maxCoeff()+1);
|
||||
|
||||
// Loop over faces
|
||||
for(int i = 0;i<F.rows();i++)
|
||||
{
|
||||
// Loop over this face
|
||||
for(int j = 0;j<F.cols();j++)
|
||||
{
|
||||
// Get indices of edge: s --> d
|
||||
int s = F(i,j);
|
||||
int d = F(i,(j+1)%F.cols());
|
||||
A.at(s).push_back(d);
|
||||
A.at(d).push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove duplicates
|
||||
for(int i=0; i<(int)A.size();++i)
|
||||
{
|
||||
std::sort(A[i].begin(), A[i].end());
|
||||
A[i].erase(std::unique(A[i].begin(), A[i].end()), A[i].end());
|
||||
}
|
||||
|
||||
// If needed, sort every VV
|
||||
if (sorted)
|
||||
{
|
||||
// Loop over faces
|
||||
|
||||
// for every vertex v store a set of ordered edges not incident to v that belongs to triangle incident on v.
|
||||
std::vector<std::vector<std::vector<int> > > SR;
|
||||
SR.resize(A.size());
|
||||
|
||||
for(int i = 0;i<F.rows();i++)
|
||||
{
|
||||
// Loop over this face
|
||||
for(int j = 0;j<F.cols();j++)
|
||||
{
|
||||
// Get indices of edge: s --> d
|
||||
int s = F(i,j);
|
||||
int d = F(i,(j+1)%F.cols());
|
||||
// Get index of opposing vertex v
|
||||
int v = F(i,(j+2)%F.cols());
|
||||
|
||||
std::vector<int> e(2);
|
||||
e[0] = d;
|
||||
e[1] = v;
|
||||
SR[s].push_back(e);
|
||||
}
|
||||
}
|
||||
|
||||
for(int v=0; v<(int)SR.size();++v)
|
||||
{
|
||||
std::vector<IndexVector>& vv = A.at(v);
|
||||
std::vector<std::vector<int> >& sr = SR[v];
|
||||
|
||||
std::vector<std::vector<int> > pn = sr;
|
||||
|
||||
// Compute previous/next for every element in sr
|
||||
for(int i=0;i<(int)sr.size();++i)
|
||||
{
|
||||
int a = sr[i][0];
|
||||
int b = sr[i][1];
|
||||
|
||||
// search for previous
|
||||
int p = -1;
|
||||
for(int j=0;j<(int)sr.size();++j)
|
||||
if(sr[j][1] == a)
|
||||
p = j;
|
||||
pn[i][0] = p;
|
||||
|
||||
// search for next
|
||||
int n = -1;
|
||||
for(int j=0;j<(int)sr.size();++j)
|
||||
if(sr[j][0] == b)
|
||||
n = j;
|
||||
pn[i][1] = n;
|
||||
|
||||
}
|
||||
|
||||
// assume manifoldness (look for beginning of a single chain)
|
||||
int c = 0;
|
||||
for(int j=0; j<=(int)sr.size();++j)
|
||||
if (pn[c][0] != -1)
|
||||
c = pn[c][0];
|
||||
|
||||
if (pn[c][0] == -1) // border case
|
||||
{
|
||||
// finally produce the new vv relation
|
||||
for(int j=0; j<(int)sr.size();++j)
|
||||
{
|
||||
vv[j] = sr[c][0];
|
||||
if (pn[c][1] != -1)
|
||||
c = pn[c][1];
|
||||
}
|
||||
vv.back() = sr[c][1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// finally produce the new vv relation
|
||||
for(int j=0; j<(int)sr.size();++j)
|
||||
{
|
||||
vv[j] = sr[c][0];
|
||||
|
||||
c = pn[c][1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Index>
|
||||
IGL_INLINE void igl::adjacency_list(
|
||||
const std::vector<std::vector<Index> > & F,
|
||||
std::vector<std::vector<Index> >& A)
|
||||
{
|
||||
A.clear();
|
||||
|
||||
// Find maxCoeff
|
||||
Index maxCoeff = 0;
|
||||
for(const auto &vec : F)
|
||||
{
|
||||
for(int coeff : vec)
|
||||
{
|
||||
maxCoeff = std::max(coeff, maxCoeff);
|
||||
}
|
||||
}
|
||||
A.resize(maxCoeff + 1);
|
||||
|
||||
// Loop over faces
|
||||
for(int i = 0;i<F.size();i++)
|
||||
{
|
||||
// Loop over this face
|
||||
for(int j = 0;j<F[i].size();j++)
|
||||
{
|
||||
// Get indices of edge: s --> d
|
||||
int s = F[i][j];
|
||||
int d = F[i][(j+1)%F[i].size()];
|
||||
A.at(s).push_back(d);
|
||||
A.at(d).push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove duplicates
|
||||
for(int i=0; i<(int)A.size();++i)
|
||||
{
|
||||
std::sort(A[i].begin(), A[i].end());
|
||||
A[i].erase(std::unique(A[i].begin(), A[i].end()), A[i].end());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::adjacency_list<Eigen::Matrix<int, -1, 2, 0, -1, 2>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, bool);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::adjacency_list<Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, bool);
|
||||
template void igl::adjacency_list<Eigen::Matrix<int, -1, 3, 0, -1, 3>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, bool);
|
||||
template void igl::adjacency_list<class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned int>(class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1> > const &, class std::vector<class std::vector<unsigned int, class std::allocator<unsigned int> >, class std::allocator<class std::vector<unsigned int, class std::allocator<unsigned int> > > > &, bool);
|
||||
template void igl::adjacency_list<int>(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
|
||||
#endif
|
||||
@@ -1,125 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "adjacency_matrix.h"
|
||||
|
||||
#include "verbose.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
template <typename DerivedF, typename T>
|
||||
IGL_INLINE void igl::adjacency_matrix(
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
Eigen::SparseMatrix<T>& A)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
typedef typename DerivedF::Scalar Index;
|
||||
|
||||
typedef Triplet<T> IJV;
|
||||
vector<IJV > ijv;
|
||||
ijv.reserve(F.size()*2);
|
||||
// Loop over **simplex** (i.e., **not quad**)
|
||||
for(int i = 0;i<F.rows();i++)
|
||||
{
|
||||
// Loop over this **simplex**
|
||||
for(int j = 0;j<F.cols();j++)
|
||||
for(int k = j+1;k<F.cols();k++)
|
||||
{
|
||||
// Get indices of edge: s --> d
|
||||
Index s = F(i,j);
|
||||
Index d = F(i,k);
|
||||
ijv.push_back(IJV(s,d,1));
|
||||
ijv.push_back(IJV(d,s,1));
|
||||
}
|
||||
}
|
||||
|
||||
const Index n = F.maxCoeff()+1;
|
||||
A.resize(n,n);
|
||||
switch(F.cols())
|
||||
{
|
||||
case 3:
|
||||
A.reserve(6*(F.maxCoeff()+1));
|
||||
break;
|
||||
case 4:
|
||||
A.reserve(26*(F.maxCoeff()+1));
|
||||
break;
|
||||
}
|
||||
A.setFromTriplets(ijv.begin(),ijv.end());
|
||||
|
||||
// Force all non-zeros to be one
|
||||
|
||||
// Iterate over outside
|
||||
for(int k=0; k<A.outerSize(); ++k)
|
||||
{
|
||||
// Iterate over inside
|
||||
for(typename Eigen::SparseMatrix<T>::InnerIterator it (A,k); it; ++it)
|
||||
{
|
||||
assert(it.value() != 0);
|
||||
A.coeffRef(it.row(),it.col()) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename DerivedI, typename DerivedC, typename T>
|
||||
IGL_INLINE void igl::adjacency_matrix(
|
||||
const Eigen::MatrixBase<DerivedI> & I,
|
||||
const Eigen::MatrixBase<DerivedC> & C,
|
||||
Eigen::SparseMatrix<T>& A)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
|
||||
typedef Triplet<T> IJV;
|
||||
vector<IJV > ijv;
|
||||
ijv.reserve(C(C.size()-1)*2);
|
||||
typedef typename DerivedI::Scalar Index;
|
||||
const Index n = I.maxCoeff()+1;
|
||||
{
|
||||
// loop over polygons
|
||||
for(Index p = 0;p<C.size()-1;p++)
|
||||
{
|
||||
// number of edges
|
||||
const Index np = C(p+1)-C(p);
|
||||
// loop over edges
|
||||
for(Index c = 0;c<np;c++)
|
||||
{
|
||||
const Index i = I(C(p)+c);
|
||||
const Index j = I(C(p)+((c+1)%np));
|
||||
ijv.emplace_back(i,j,1);
|
||||
ijv.emplace_back(j,i,1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
A.resize(n,n);
|
||||
A.reserve(6*n);
|
||||
A.setFromTriplets(ijv.begin(),ijv.end());
|
||||
|
||||
// Force all non-zeros to be one
|
||||
|
||||
// Iterate over outside
|
||||
for(int k=0; k<A.outerSize(); ++k)
|
||||
{
|
||||
// Iterate over inside
|
||||
for(typename Eigen::SparseMatrix<T>::InnerIterator it (A,k); it; ++it)
|
||||
{
|
||||
assert(it.value() != 0);
|
||||
A.coeffRef(it.row(),it.col()) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<int, 0, int>& );
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, -1, 0, -1, -1>, bool>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<bool, 0, int>&);
|
||||
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<int, 0, int>&);
|
||||
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, 3, 0, -1, 3>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::SparseMatrix<int, 0, int>&);
|
||||
#endif
|
||||
@@ -1,26 +0,0 @@
|
||||
// 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 "all.h"
|
||||
#include "redux.h"
|
||||
|
||||
|
||||
template <typename AType, typename DerivedB>
|
||||
IGL_INLINE void igl::all(
|
||||
const Eigen::SparseMatrix<AType> & A,
|
||||
const int dim,
|
||||
Eigen::PlainObjectBase<DerivedB>& B)
|
||||
{
|
||||
typedef typename DerivedB::Scalar Scalar;
|
||||
igl::redux(A,dim,[](Scalar a, Scalar b){ return a && b!=0;},B);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "all_pairs_distances.h"
|
||||
#include <Eigen/Dense>
|
||||
|
||||
template <typename Mat>
|
||||
IGL_INLINE void igl::all_pairs_distances(
|
||||
const Mat & V,
|
||||
const Mat & U,
|
||||
const bool squared,
|
||||
Mat & D)
|
||||
{
|
||||
// dimension should be the same
|
||||
assert(V.cols() == U.cols());
|
||||
// resize output
|
||||
D.resize(V.rows(),U.rows());
|
||||
for(int i = 0;i<V.rows();i++)
|
||||
{
|
||||
for(int j=0;j<U.rows();j++)
|
||||
{
|
||||
D(i,j) = (V.row(i)-U.row(j)).squaredNorm();
|
||||
if(!squared)
|
||||
{
|
||||
D(i,j) = sqrt(D(i,j));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::all_pairs_distances<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, bool, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
|
||||
#endif
|
||||
@@ -1,139 +0,0 @@
|
||||
// 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 "ambient_occlusion.h"
|
||||
#include "random_dir.h"
|
||||
#include "ray_mesh_intersect.h"
|
||||
#include "EPS.h"
|
||||
#include "Hit.h"
|
||||
#include "parallel_for.h"
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
template <
|
||||
typename DerivedP,
|
||||
typename DerivedN,
|
||||
typename DerivedS >
|
||||
IGL_INLINE void igl::ambient_occlusion(
|
||||
const std::function<
|
||||
bool(
|
||||
const Eigen::Vector3f&,
|
||||
const Eigen::Vector3f&)
|
||||
> & shoot_ray,
|
||||
const Eigen::MatrixBase<DerivedP> & P,
|
||||
const Eigen::MatrixBase<DerivedN> & N,
|
||||
const int num_samples,
|
||||
Eigen::PlainObjectBase<DerivedS> & S)
|
||||
{
|
||||
using namespace Eigen;
|
||||
const int n = P.rows();
|
||||
// Resize output
|
||||
S.resize(n,1);
|
||||
// Embree seems to be parallel when constructing but not when tracing rays
|
||||
const MatrixXf D = random_dir_stratified(num_samples).cast<float>();
|
||||
|
||||
const auto & inner = [&P,&N,&num_samples,&D,&S,&shoot_ray](const int p)
|
||||
{
|
||||
const Vector3f origin = P.row(p).template cast<float>();
|
||||
const Vector3f normal = N.row(p).template cast<float>();
|
||||
int num_hits = 0;
|
||||
for(int s = 0;s<num_samples;s++)
|
||||
{
|
||||
Vector3f d = D.row(s);
|
||||
if(d.dot(normal) < 0)
|
||||
{
|
||||
// reverse ray
|
||||
d *= -1;
|
||||
}
|
||||
if(shoot_ray(origin,d))
|
||||
{
|
||||
num_hits++;
|
||||
}
|
||||
}
|
||||
S(p) = (double)num_hits/(double)num_samples;
|
||||
};
|
||||
parallel_for(n,inner,1000);
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
int DIM,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename DerivedN,
|
||||
typename DerivedS >
|
||||
IGL_INLINE void igl::ambient_occlusion(
|
||||
const igl::AABB<DerivedV,DIM> & aabb,
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const Eigen::MatrixBase<DerivedP> & P,
|
||||
const Eigen::MatrixBase<DerivedN> & N,
|
||||
const int num_samples,
|
||||
Eigen::PlainObjectBase<DerivedS> & S)
|
||||
{
|
||||
const auto & shoot_ray = [&aabb,&V,&F](
|
||||
const Eigen::Vector3f& _s,
|
||||
const Eigen::Vector3f& dir)->bool
|
||||
{
|
||||
Eigen::Vector3f s = _s+1e-4*dir;
|
||||
igl::Hit hit;
|
||||
return aabb.intersect_ray(
|
||||
V,
|
||||
F,
|
||||
s .cast<typename DerivedV::Scalar>().eval(),
|
||||
dir.cast<typename DerivedV::Scalar>().eval(),
|
||||
hit);
|
||||
};
|
||||
return ambient_occlusion(shoot_ray,P,N,num_samples,S);
|
||||
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename DerivedN,
|
||||
typename DerivedS >
|
||||
IGL_INLINE void igl::ambient_occlusion(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const Eigen::MatrixBase<DerivedP> & P,
|
||||
const Eigen::MatrixBase<DerivedN> & N,
|
||||
const int num_samples,
|
||||
Eigen::PlainObjectBase<DerivedS> & S)
|
||||
{
|
||||
if(F.rows() < 100)
|
||||
{
|
||||
// Super naive
|
||||
const auto & shoot_ray = [&V,&F](
|
||||
const Eigen::Vector3f& _s,
|
||||
const Eigen::Vector3f& dir)->bool
|
||||
{
|
||||
Eigen::Vector3f s = _s+1e-4*dir;
|
||||
igl::Hit hit;
|
||||
return ray_mesh_intersect(s,dir,V,F,hit);
|
||||
};
|
||||
return ambient_occlusion(shoot_ray,P,N,num_samples,S);
|
||||
}
|
||||
AABB<DerivedV,3> aabb;
|
||||
aabb.init(V,F);
|
||||
return ambient_occlusion(aabb,V,F,P,N,num_samples,S);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::ambient_occlusion<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::ambient_occlusion<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -1,20 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "angular_distance.h"
|
||||
#include "EPS.h"
|
||||
#include "PI.h"
|
||||
IGL_INLINE double igl::angular_distance(
|
||||
const Eigen::Quaterniond & A,
|
||||
const Eigen::Quaterniond & B)
|
||||
{
|
||||
assert(fabs(A.norm()-1)<FLOAT_EPS && "A should be unit norm");
|
||||
assert(fabs(B.norm()-1)<FLOAT_EPS && "B should be unit norm");
|
||||
//// acos is always in [0,2*pi)
|
||||
//return acos(fabs(A.dot(B)));
|
||||
return fmod(2.*acos(A.dot(B)),2.*PI);
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
// 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 "any.h"
|
||||
#include "redux.h"
|
||||
|
||||
|
||||
template <typename AType, typename DerivedB>
|
||||
IGL_INLINE void igl::any(
|
||||
const Eigen::SparseMatrix<AType> & A,
|
||||
const int dim,
|
||||
Eigen::PlainObjectBase<DerivedB>& B)
|
||||
{
|
||||
typedef typename DerivedB::Scalar Scalar;
|
||||
igl::redux(A,dim,[](Scalar a, Scalar b){ return a || b!=0;},B);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::any<bool, Eigen::Array<bool, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<bool, 0, int> const&, int, Eigen::PlainObjectBase<Eigen::Array<bool, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
@@ -1,306 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "arap.h"
|
||||
#include "colon.h"
|
||||
#include "cotmatrix.h"
|
||||
#include "massmatrix.h"
|
||||
#include "group_sum_matrix.h"
|
||||
#include "covariance_scatter_matrix.h"
|
||||
#include "speye.h"
|
||||
#include "mode.h"
|
||||
#include "project_isometrically_to_plane.h"
|
||||
#include "slice.h"
|
||||
#include "arap_rhs.h"
|
||||
#include "repdiag.h"
|
||||
#include "columnize.h"
|
||||
#include "fit_rotations.h"
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
template <typename Scalar>
|
||||
using MatrixXX = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename Derivedb>
|
||||
IGL_INLINE bool igl::arap_precomputation(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const int dim,
|
||||
const Eigen::MatrixBase<Derivedb> & b,
|
||||
ARAPData & data)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
typedef typename DerivedV::Scalar Scalar;
|
||||
typedef typename DerivedF::Scalar Integer;
|
||||
// number of vertices
|
||||
const int n = V.rows();
|
||||
data.n = n;
|
||||
assert((b.size() == 0 || b.maxCoeff() < n) && "b out of bounds");
|
||||
assert((b.size() == 0 || b.minCoeff() >=0) && "b out of bounds");
|
||||
// remember b
|
||||
data.b = b;
|
||||
//assert(F.cols() == 3 && "For now only triangles");
|
||||
// dimension
|
||||
//const int dim = V.cols();
|
||||
assert((dim == 3 || dim ==2) && "dim should be 2 or 3");
|
||||
data.dim = dim;
|
||||
//assert(dim == 3 && "Only 3d supported");
|
||||
// Defaults
|
||||
data.f_ext = MatrixXd::Zero(n,data.dim);
|
||||
|
||||
assert(data.dim <= V.cols() && "solve dim should be <= embedding");
|
||||
bool flat = (V.cols() - data.dim)==1;
|
||||
|
||||
MatrixXX<Scalar> plane_V;
|
||||
MatrixXX<Integer> plane_F;
|
||||
typedef SparseMatrix<Scalar> SparseMatrixS;
|
||||
SparseMatrixS ref_map,ref_map_dim;
|
||||
if(flat)
|
||||
{
|
||||
project_isometrically_to_plane(V,F,plane_V,plane_F,ref_map);
|
||||
repdiag(ref_map,dim,ref_map_dim);
|
||||
}
|
||||
const MatrixXX<Scalar>& ref_V = (flat?plane_V:V);
|
||||
const MatrixXX<Integer>& ref_F = (flat?plane_F:F);
|
||||
SparseMatrixS L;
|
||||
cotmatrix(V,F,L);
|
||||
|
||||
ARAPEnergyType eff_energy = data.energy;
|
||||
if(eff_energy == ARAP_ENERGY_TYPE_DEFAULT)
|
||||
{
|
||||
switch(F.cols())
|
||||
{
|
||||
case 3:
|
||||
if(data.dim == 3)
|
||||
{
|
||||
eff_energy = ARAP_ENERGY_TYPE_SPOKES_AND_RIMS;
|
||||
}else
|
||||
{
|
||||
eff_energy = ARAP_ENERGY_TYPE_ELEMENTS;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
eff_energy = ARAP_ENERGY_TYPE_ELEMENTS;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get covariance scatter matrix, when applied collects the covariance
|
||||
// matrices used to fit rotations to during optimization
|
||||
covariance_scatter_matrix(ref_V,ref_F,eff_energy,data.CSM);
|
||||
if(flat)
|
||||
{
|
||||
data.CSM = (data.CSM * ref_map_dim.transpose()).eval();
|
||||
}
|
||||
assert(data.CSM.cols() == V.rows()*data.dim);
|
||||
|
||||
// Get group sum scatter matrix, when applied sums all entries of the same
|
||||
// group according to G
|
||||
SparseMatrix<double> G_sum;
|
||||
if(data.G.size() == 0)
|
||||
{
|
||||
if(eff_energy == ARAP_ENERGY_TYPE_ELEMENTS)
|
||||
{
|
||||
speye(F.rows(),G_sum);
|
||||
}else
|
||||
{
|
||||
speye(n,G_sum);
|
||||
}
|
||||
}else
|
||||
{
|
||||
// groups are defined per vertex, convert to per face using mode
|
||||
if(eff_energy == ARAP_ENERGY_TYPE_ELEMENTS)
|
||||
{
|
||||
Eigen::Matrix<int,Eigen::Dynamic,1> GG;
|
||||
MatrixXi GF(F.rows(),F.cols());
|
||||
for(int j = 0;j<F.cols();j++)
|
||||
{
|
||||
Matrix<int,Eigen::Dynamic,1> GFj;
|
||||
slice(data.G,F.col(j),GFj);
|
||||
GF.col(j) = GFj;
|
||||
}
|
||||
mode<int>(GF,2,GG);
|
||||
data.G=GG;
|
||||
}
|
||||
//printf("group_sum_matrix()\n");
|
||||
group_sum_matrix(data.G,G_sum);
|
||||
}
|
||||
SparseMatrix<double> G_sum_dim;
|
||||
repdiag(G_sum,data.dim,G_sum_dim);
|
||||
assert(G_sum_dim.cols() == data.CSM.rows());
|
||||
data.CSM = (G_sum_dim * data.CSM).eval();
|
||||
|
||||
|
||||
arap_rhs(ref_V,ref_F,data.dim,eff_energy,data.K);
|
||||
if(flat)
|
||||
{
|
||||
data.K = (ref_map_dim * data.K).eval();
|
||||
}
|
||||
assert(data.K.rows() == data.n*data.dim);
|
||||
|
||||
SparseMatrix<double> Q = (-L).eval();
|
||||
|
||||
if(data.with_dynamics)
|
||||
{
|
||||
const double h = data.h;
|
||||
assert(h != 0);
|
||||
SparseMatrix<double> M;
|
||||
massmatrix(V,F,MASSMATRIX_TYPE_DEFAULT,data.M);
|
||||
const double dw = (1./data.ym)*(h*h);
|
||||
SparseMatrix<double> DQ = dw * 1./(h*h)*data.M;
|
||||
Q += DQ;
|
||||
// Dummy external forces
|
||||
data.f_ext = MatrixXd::Zero(n,data.dim);
|
||||
data.vel = MatrixXd::Zero(n,data.dim);
|
||||
}
|
||||
|
||||
return min_quad_with_fixed_precompute(
|
||||
Q,b,SparseMatrix<double>(),true,data.solver_data);
|
||||
}
|
||||
|
||||
template <
|
||||
typename Derivedbc,
|
||||
typename DerivedU>
|
||||
IGL_INLINE bool igl::arap_solve(
|
||||
const Eigen::MatrixBase<Derivedbc> & bc,
|
||||
ARAPData & data,
|
||||
Eigen::MatrixBase<DerivedU> & U)
|
||||
{
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
assert(data.b.size() == bc.rows());
|
||||
assert(U.size() != 0 && "U cannot be empty");
|
||||
assert(U.cols() == data.dim && "U.cols() match data.dim");
|
||||
if (bc.size() > 0) {
|
||||
assert(bc.cols() == data.dim && "bc.cols() match data.dim");
|
||||
}
|
||||
const int n = data.n;
|
||||
int iter = 0;
|
||||
// changes each arap iteration
|
||||
MatrixXd U_prev = U;
|
||||
// doesn't change for fixed with_dynamics timestep
|
||||
MatrixXd U0;
|
||||
if(data.with_dynamics)
|
||||
{
|
||||
U0 = U_prev;
|
||||
}
|
||||
while(iter < data.max_iter)
|
||||
{
|
||||
U_prev = U;
|
||||
// enforce boundary conditions exactly
|
||||
for(int bi = 0;bi<bc.rows();bi++)
|
||||
{
|
||||
U.row(data.b(bi)) = bc.row(bi);
|
||||
}
|
||||
|
||||
const auto & Udim = U.replicate(data.dim,1);
|
||||
assert(U.cols() == data.dim);
|
||||
// As if U.col(2) was 0
|
||||
MatrixXd S = data.CSM * Udim;
|
||||
// THIS NORMALIZATION IS IMPORTANT TO GET SINGLE PRECISION SVD CODE TO WORK
|
||||
// CORRECTLY.
|
||||
S /= S.array().abs().maxCoeff();
|
||||
|
||||
const int Rdim = data.dim;
|
||||
MatrixXd R(Rdim,data.CSM.rows());
|
||||
if(R.rows() == 2)
|
||||
{
|
||||
fit_rotations_planar(S,R);
|
||||
}else
|
||||
{
|
||||
fit_rotations(S,true,R);
|
||||
//#ifdef __SSE__ // fit_rotations_SSE will convert to float if necessary
|
||||
// fit_rotations_SSE(S,R);
|
||||
//#else
|
||||
// fit_rotations(S,true,R);
|
||||
//#endif
|
||||
}
|
||||
//for(int k = 0;k<(data.CSM.rows()/dim);k++)
|
||||
//{
|
||||
// R.block(0,dim*k,dim,dim) = MatrixXd::Identity(dim,dim);
|
||||
//}
|
||||
|
||||
|
||||
// Number of rotations: #vertices or #elements
|
||||
int num_rots = data.K.cols()/Rdim/Rdim;
|
||||
// distribute group rotations to vertices in each group
|
||||
MatrixXd eff_R;
|
||||
if(data.G.size() == 0)
|
||||
{
|
||||
// copy...
|
||||
eff_R = R;
|
||||
}else
|
||||
{
|
||||
eff_R.resize(Rdim,num_rots*Rdim);
|
||||
for(int r = 0;r<num_rots;r++)
|
||||
{
|
||||
eff_R.block(0,Rdim*r,Rdim,Rdim) =
|
||||
R.block(0,Rdim*data.G(r),Rdim,Rdim);
|
||||
}
|
||||
}
|
||||
|
||||
MatrixXd Dl;
|
||||
if(data.with_dynamics)
|
||||
{
|
||||
assert(data.M.rows() == n &&
|
||||
"No mass matrix. Call arap_precomputation if changing with_dynamics");
|
||||
const double h = data.h;
|
||||
assert(h != 0);
|
||||
//Dl = 1./(h*h*h)*M*(-2.*V0 + Vm1) - fext;
|
||||
// data.vel = (V0-Vm1)/h
|
||||
// h*data.vel = (V0-Vm1)
|
||||
// -h*data.vel = -V0+Vm1)
|
||||
// -V0-h*data.vel = -2V0+Vm1
|
||||
const double dw = (1./data.ym)*(h*h);
|
||||
Dl = dw * (1./(h*h)*data.M*(-U0 - h*data.vel) - data.f_ext);
|
||||
}
|
||||
|
||||
VectorXd Rcol;
|
||||
columnize(eff_R,num_rots,2,Rcol);
|
||||
VectorXd Bcol = -data.K * Rcol;
|
||||
assert(Bcol.size() == data.n*data.dim);
|
||||
for(int c = 0;c<data.dim;c++)
|
||||
{
|
||||
VectorXd Uc,Bc,bcc,Beq;
|
||||
Bc = Bcol.block(c*n,0,n,1);
|
||||
if(data.with_dynamics)
|
||||
{
|
||||
Bc += Dl.col(c);
|
||||
}
|
||||
if(bc.size()>0)
|
||||
{
|
||||
bcc = bc.col(c);
|
||||
}
|
||||
min_quad_with_fixed_solve(
|
||||
data.solver_data,
|
||||
Bc,bcc,Beq,
|
||||
Uc);
|
||||
U.col(c) = Uc;
|
||||
}
|
||||
|
||||
iter++;
|
||||
}
|
||||
if(data.with_dynamics)
|
||||
{
|
||||
// Keep track of velocity for next time
|
||||
data.vel = (U-U0)/data.h;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
template bool igl::arap_solve<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, igl::ARAPData&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template bool igl::arap_precomputation<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::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, igl::ARAPData&);
|
||||
#endif
|
||||
@@ -1,883 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "arap_dof.h"
|
||||
|
||||
#include "cotmatrix.h"
|
||||
#include "massmatrix.h"
|
||||
#include "speye.h"
|
||||
#include "repdiag.h"
|
||||
#include "repmat.h"
|
||||
#include "slice.h"
|
||||
#include "colon.h"
|
||||
#include "is_sparse.h"
|
||||
#include "mode.h"
|
||||
#include "is_symmetric.h"
|
||||
#include "group_sum_matrix.h"
|
||||
#include "arap_rhs.h"
|
||||
#include "covariance_scatter_matrix.h"
|
||||
#include "fit_rotations.h"
|
||||
|
||||
#include "verbose.h"
|
||||
#include "print_ijv.h"
|
||||
|
||||
//#include "MKLEigenInterface.h"
|
||||
#include "kkt_inverse.h"
|
||||
#include "get_seconds.h"
|
||||
#include "columnize.h"
|
||||
|
||||
// defined if no early exit is supported, i.e., always take a fixed number of iterations
|
||||
#define IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
|
||||
|
||||
// A careful derivation of this implementation is given in the corresponding
|
||||
// matlab function arap_dof.m
|
||||
template <typename LbsMatrixType, typename SSCALAR>
|
||||
IGL_INLINE bool igl::arap_dof_precomputation(
|
||||
const Eigen::MatrixXd & V,
|
||||
const Eigen::MatrixXi & F,
|
||||
const LbsMatrixType & M,
|
||||
const Eigen::Matrix<int,Eigen::Dynamic,1> & G,
|
||||
ArapDOFData<LbsMatrixType, SSCALAR> & data)
|
||||
{
|
||||
using namespace Eigen;
|
||||
typedef Matrix<SSCALAR, Dynamic, Dynamic> MatrixXS;
|
||||
// number of mesh (domain) vertices
|
||||
int n = V.rows();
|
||||
// cache problem size
|
||||
data.n = n;
|
||||
// dimension of mesh
|
||||
data.dim = V.cols();
|
||||
assert(data.dim == M.rows()/n);
|
||||
assert(data.dim*n == M.rows());
|
||||
if(data.dim == 3)
|
||||
{
|
||||
// Check if z-coordinate is all zeros
|
||||
if(V.col(2).minCoeff() == 0 && V.col(2).maxCoeff() == 0)
|
||||
{
|
||||
data.effective_dim = 2;
|
||||
}
|
||||
}else
|
||||
{
|
||||
data.effective_dim = data.dim;
|
||||
}
|
||||
// Number of handles
|
||||
data.m = M.cols()/data.dim/(data.dim+1);
|
||||
assert(data.m*data.dim*(data.dim+1) == M.cols());
|
||||
//assert(m == C.rows());
|
||||
|
||||
//printf("n=%d; dim=%d; m=%d;\n",n,data.dim,data.m);
|
||||
|
||||
// Build cotangent laplacian
|
||||
SparseMatrix<double> Lcot;
|
||||
//printf("cotmatrix()\n");
|
||||
cotmatrix(V,F,Lcot);
|
||||
// Discrete laplacian (should be minus matlab version)
|
||||
SparseMatrix<double> Lapl = -2.0*Lcot;
|
||||
#ifdef EXTREME_VERBOSE
|
||||
cout<<"LaplIJV=["<<endl;print_ijv(Lapl,1);cout<<endl<<"];"<<
|
||||
endl<<"Lapl=sparse(LaplIJV(:,1),LaplIJV(:,2),LaplIJV(:,3),"<<
|
||||
Lapl.rows()<<","<<Lapl.cols()<<");"<<endl;
|
||||
#endif
|
||||
|
||||
// Get group sum scatter matrix, when applied sums all entries of the same
|
||||
// group according to G
|
||||
SparseMatrix<double> G_sum;
|
||||
if(G.size() == 0)
|
||||
{
|
||||
speye(n,G_sum);
|
||||
}else
|
||||
{
|
||||
// groups are defined per vertex, convert to per face using mode
|
||||
Eigen::Matrix<int,Eigen::Dynamic,1> GG;
|
||||
if(data.energy == ARAP_ENERGY_TYPE_ELEMENTS)
|
||||
{
|
||||
MatrixXi GF(F.rows(),F.cols());
|
||||
for(int j = 0;j<F.cols();j++)
|
||||
{
|
||||
Matrix<int,Eigen::Dynamic,1> GFj;
|
||||
slice(G,F.col(j),GFj);
|
||||
GF.col(j) = GFj;
|
||||
}
|
||||
mode<int>(GF,2,GG);
|
||||
}else
|
||||
{
|
||||
GG=G;
|
||||
}
|
||||
//printf("group_sum_matrix()\n");
|
||||
group_sum_matrix(GG,G_sum);
|
||||
}
|
||||
|
||||
#ifdef EXTREME_VERBOSE
|
||||
cout<<"G_sumIJV=["<<endl;print_ijv(G_sum,1);cout<<endl<<"];"<<
|
||||
endl<<"G_sum=sparse(G_sumIJV(:,1),G_sumIJV(:,2),G_sumIJV(:,3),"<<
|
||||
G_sum.rows()<<","<<G_sum.cols()<<");"<<endl;
|
||||
#endif
|
||||
|
||||
// Get covariance scatter matrix, when applied collects the covariance matrices
|
||||
// used to fit rotations to during optimization
|
||||
SparseMatrix<double> CSM;
|
||||
//printf("covariance_scatter_matrix()\n");
|
||||
covariance_scatter_matrix(V,F,data.energy,CSM);
|
||||
#ifdef EXTREME_VERBOSE
|
||||
cout<<"CSMIJV=["<<endl;print_ijv(CSM,1);cout<<endl<<"];"<<
|
||||
endl<<"CSM=sparse(CSMIJV(:,1),CSMIJV(:,2),CSMIJV(:,3),"<<
|
||||
CSM.rows()<<","<<CSM.cols()<<");"<<endl;
|
||||
#endif
|
||||
|
||||
|
||||
// Build the covariance matrix "constructor". This is a set of *scatter*
|
||||
// matrices that when multiplied on the right by column of the transformation
|
||||
// matrix entries (the degrees of freedom) L, we get a stack of dim by 1
|
||||
// covariance matrix column, with a column in the stack for each rotation
|
||||
// *group*. The output is a list of matrices because we construct each column
|
||||
// in the stack of covariance matrices with an independent matrix-vector
|
||||
// multiplication.
|
||||
//
|
||||
// We want to build S which is a stack of dim by dim covariance matrices.
|
||||
// Thus S is dim*g by dim, where dim is the number of dimensions and g is the
|
||||
// number of groups. We can precompute dim matrices CSM_M such that column i
|
||||
// in S is computed as S(:,i) = CSM_M{i} * L, where L is a column of the
|
||||
// skinning transformation matrix values. To be clear, the covariance matrix
|
||||
// for group k is then given as the dim by dim matrix pulled from the stack:
|
||||
// S((k-1)*dim + 1:dim,:)
|
||||
|
||||
// Apply group sum to each dimension's block of covariance scatter matrix
|
||||
SparseMatrix<double> G_sum_dim;
|
||||
repdiag(G_sum,data.dim,G_sum_dim);
|
||||
CSM = (G_sum_dim * CSM).eval();
|
||||
#ifdef EXTREME_VERBOSE
|
||||
cout<<"CSMIJV=["<<endl;print_ijv(CSM,1);cout<<endl<<"];"<<
|
||||
endl<<"CSM=sparse(CSMIJV(:,1),CSMIJV(:,2),CSMIJV(:,3),"<<
|
||||
CSM.rows()<<","<<CSM.cols()<<");"<<endl;
|
||||
#endif
|
||||
|
||||
//printf("CSM_M()\n");
|
||||
// Precompute CSM times M for each dimension
|
||||
data.CSM_M.resize(data.dim);
|
||||
#ifdef EXTREME_VERBOSE
|
||||
cout<<"data.CSM_M = cell("<<data.dim<<",1);"<<endl;
|
||||
#endif
|
||||
// span of integers from 0 to n-1
|
||||
Eigen::Matrix<int,Eigen::Dynamic,1> span_n(n);
|
||||
for(int i = 0;i<n;i++)
|
||||
{
|
||||
span_n(i) = i;
|
||||
}
|
||||
|
||||
// span of integers from 0 to M.cols()-1
|
||||
Eigen::Matrix<int,Eigen::Dynamic,1> span_mlbs_cols(M.cols());
|
||||
for(int i = 0;i<M.cols();i++)
|
||||
{
|
||||
span_mlbs_cols(i) = i;
|
||||
}
|
||||
|
||||
// number of groups
|
||||
int k = CSM.rows()/data.dim;
|
||||
for(int i = 0;i<data.dim;i++)
|
||||
{
|
||||
//printf("CSM_M(): Mi\n");
|
||||
LbsMatrixType M_i;
|
||||
//printf("CSM_M(): slice\n");
|
||||
slice(M,(span_n.array()+i*n).matrix().eval(),span_mlbs_cols,M_i);
|
||||
LbsMatrixType M_i_dim;
|
||||
data.CSM_M[i].resize(k*data.dim,data.m*data.dim*(data.dim+1));
|
||||
assert(data.CSM_M[i].cols() == M.cols());
|
||||
for(int j = 0;j<data.dim;j++)
|
||||
{
|
||||
SparseMatrix<double> CSMj;
|
||||
//printf("CSM_M(): slice\n");
|
||||
slice(
|
||||
CSM,
|
||||
colon<int>(j*k,(j+1)*k-1),
|
||||
colon<int>(j*n,(j+1)*n-1),
|
||||
CSMj);
|
||||
assert(CSMj.rows() == k);
|
||||
assert(CSMj.cols() == n);
|
||||
LbsMatrixType CSMjM_i = CSMj * M_i;
|
||||
if(is_sparse(CSMjM_i))
|
||||
{
|
||||
// Convert to full
|
||||
//printf("CSM_M(): full\n");
|
||||
MatrixXd CSMjM_ifull(CSMjM_i);
|
||||
// printf("CSM_M[%d]: %d %d\n",i,data.CSM_M[i].rows(),data.CSM_M[i].cols());
|
||||
// printf("CSM_M[%d].block(%d*%d=%d,0,%d,%d): %d %d\n",i,j,k,CSMjM_i.rows(),CSMjM_i.cols(),
|
||||
// data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()).rows(),
|
||||
// data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()).cols());
|
||||
// printf("CSM_MjMi: %d %d\n",i,CSMjM_i.rows(),CSMjM_i.cols());
|
||||
// printf("CSM_MjM_ifull: %d %d\n",i,CSMjM_ifull.rows(),CSMjM_ifull.cols());
|
||||
data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()) = CSMjM_ifull;
|
||||
}else
|
||||
{
|
||||
data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()) = CSMjM_i;
|
||||
}
|
||||
}
|
||||
#ifdef EXTREME_VERBOSE
|
||||
cout<<"CSM_Mi=["<<endl<<data.CSM_M[i]<<endl<<"];"<<endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
// precompute arap_rhs matrix
|
||||
//printf("arap_rhs()\n");
|
||||
SparseMatrix<double> K;
|
||||
arap_rhs(V,F,V.cols(),data.energy,K);
|
||||
//#ifdef EXTREME_VERBOSE
|
||||
// cout<<"KIJV=["<<endl;print_ijv(K,1);cout<<endl<<"];"<<
|
||||
// endl<<"K=sparse(KIJV(:,1),KIJV(:,2),KIJV(:,3),"<<
|
||||
// K.rows()<<","<<K.cols()<<");"<<endl;
|
||||
//#endif
|
||||
// Precompute left muliplication by M and right multiplication by G_sum
|
||||
SparseMatrix<double> G_sumT = G_sum.transpose();
|
||||
SparseMatrix<double> G_sumT_dim_dim;
|
||||
repdiag(G_sumT,data.dim*data.dim,G_sumT_dim_dim);
|
||||
LbsMatrixType MT = M.transpose();
|
||||
// If this is a bottle neck then consider reordering matrix multiplication
|
||||
data.M_KG = -4.0 * (MT * (K * G_sumT_dim_dim));
|
||||
//#ifdef EXTREME_VERBOSE
|
||||
// cout<<"data.M_KGIJV=["<<endl;print_ijv(data.M_KG,1);cout<<endl<<"];"<<
|
||||
// endl<<"data.M_KG=sparse(data.M_KGIJV(:,1),data.M_KGIJV(:,2),data.M_KGIJV(:,3),"<<
|
||||
// data.M_KG.rows()<<","<<data.M_KG.cols()<<");"<<endl;
|
||||
//#endif
|
||||
|
||||
// Precompute system matrix
|
||||
//printf("A()\n");
|
||||
SparseMatrix<double> A;
|
||||
repdiag(Lapl,data.dim,A);
|
||||
data.Q = MT * (A * M);
|
||||
//#ifdef EXTREME_VERBOSE
|
||||
// cout<<"QIJV=["<<endl;print_ijv(data.Q,1);cout<<endl<<"];"<<
|
||||
// endl<<"Q=sparse(QIJV(:,1),QIJV(:,2),QIJV(:,3),"<<
|
||||
// data.Q.rows()<<","<<data.Q.cols()<<");"<<endl;
|
||||
//#endif
|
||||
|
||||
// Always do dynamics precomputation so we can hot-switch
|
||||
//if(data.with_dynamics)
|
||||
//{
|
||||
// Build cotangent laplacian
|
||||
SparseMatrix<double> Mass;
|
||||
//printf("massmatrix()\n");
|
||||
massmatrix(V,F,(F.cols()>3?MASSMATRIX_TYPE_BARYCENTRIC:MASSMATRIX_TYPE_VORONOI),Mass);
|
||||
//cout<<"MIJV=["<<endl;print_ijv(Mass,1);cout<<endl<<"];"<<
|
||||
// endl<<"M=sparse(MIJV(:,1),MIJV(:,2),MIJV(:,3),"<<
|
||||
// Mass.rows()<<","<<Mass.cols()<<");"<<endl;
|
||||
//speye(data.n,Mass);
|
||||
SparseMatrix<double> Mass_rep;
|
||||
repdiag(Mass,data.dim,Mass_rep);
|
||||
|
||||
// Multiply either side by weights matrix (should be dense)
|
||||
data.Mass_tilde = MT * Mass_rep * M;
|
||||
MatrixXd ones(data.dim*data.n,data.dim);
|
||||
for(int i = 0;i<data.n;i++)
|
||||
{
|
||||
for(int d = 0;d<data.dim;d++)
|
||||
{
|
||||
ones(i+d*data.n,d) = 1;
|
||||
}
|
||||
}
|
||||
data.fgrav = MT * (Mass_rep * ones);
|
||||
data.fext = MatrixXS::Zero(MT.rows(),1);
|
||||
//data.fgrav = MT * (ones);
|
||||
//}
|
||||
|
||||
|
||||
// This may/should be superfluous
|
||||
//printf("is_symmetric()\n");
|
||||
if(!is_symmetric(data.Q))
|
||||
{
|
||||
//printf("Fixing symmetry...\n");
|
||||
// "Fix" symmetry
|
||||
LbsMatrixType QT = data.Q.transpose();
|
||||
LbsMatrixType Q_copy = data.Q;
|
||||
data.Q = 0.5*(Q_copy+QT);
|
||||
// Check that ^^^ this really worked. It doesn't always
|
||||
//assert(is_symmetric(*Q));
|
||||
}
|
||||
|
||||
//printf("arap_dof_precomputation() succeeded... so far...\n");
|
||||
verbose("Number of handles: %i\n", data.m);
|
||||
return true;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// STATIC FUNCTIONS (These should be removed or properly defined)
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
namespace igl
|
||||
{
|
||||
// returns maximal difference of 'blok' from scalar times 3x3 identity:
|
||||
template <typename SSCALAR>
|
||||
inline static SSCALAR maxBlokErr(const Eigen::Matrix3f &blok)
|
||||
{
|
||||
SSCALAR mD;
|
||||
SSCALAR value = blok(0,0);
|
||||
SSCALAR diff1 = fabs(blok(1,1) - value);
|
||||
SSCALAR diff2 = fabs(blok(2,2) - value);
|
||||
if (diff1 > diff2) mD = diff1;
|
||||
else mD = diff2;
|
||||
|
||||
for (int v=0; v<3; v++)
|
||||
{
|
||||
for (int w=0; w<3; w++)
|
||||
{
|
||||
if (v == w)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (mD < fabs(blok(v, w)))
|
||||
{
|
||||
mD = fabs(blok(v, w));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mD;
|
||||
}
|
||||
|
||||
// converts CSM_M_SSCALAR[0], CSM_M_SSCALAR[1], CSM_M_SSCALAR[2] into one
|
||||
// "condensed" matrix CSM while checking we're not losing any information by
|
||||
// this process; specifically, returns maximal difference from scaled 3x3
|
||||
// identity blocks, which should be pretty small number
|
||||
template <typename MatrixXS>
|
||||
static typename MatrixXS::Scalar condense_CSM(
|
||||
const std::vector<MatrixXS> &CSM_M_SSCALAR,
|
||||
int numBones,
|
||||
int dim,
|
||||
MatrixXS &CSM)
|
||||
{
|
||||
const int numRows = CSM_M_SSCALAR[0].rows();
|
||||
assert(CSM_M_SSCALAR[0].cols() == dim*(dim+1)*numBones);
|
||||
assert(CSM_M_SSCALAR[1].cols() == dim*(dim+1)*numBones);
|
||||
assert(CSM_M_SSCALAR[2].cols() == dim*(dim+1)*numBones);
|
||||
assert(CSM_M_SSCALAR[1].rows() == numRows);
|
||||
assert(CSM_M_SSCALAR[2].rows() == numRows);
|
||||
|
||||
const int numCols = (dim + 1)*numBones;
|
||||
CSM.resize(numRows, numCols);
|
||||
|
||||
typedef typename MatrixXS::Scalar SSCALAR;
|
||||
SSCALAR maxDiff = 0.0f;
|
||||
|
||||
for (int r=0; r<numRows; r++)
|
||||
{
|
||||
for (int coord=0; coord<dim+1; coord++)
|
||||
{
|
||||
for (int b=0; b<numBones; b++)
|
||||
{
|
||||
// this is just a test if we really have a multiple of 3x3 identity
|
||||
Eigen::Matrix3f blok;
|
||||
for (int v=0; v<3; v++)
|
||||
{
|
||||
for (int w=0; w<3; w++)
|
||||
{
|
||||
blok(v,w) = CSM_M_SSCALAR[v](r, coord*(numBones*dim) + b + w*numBones);
|
||||
}
|
||||
}
|
||||
|
||||
//SSCALAR value[3];
|
||||
//for (int v=0; v<3; v++)
|
||||
// CSM_M_SSCALAR[v](r, coord*(numBones*dim) + b + v*numBones);
|
||||
|
||||
SSCALAR mD = maxBlokErr<SSCALAR>(blok);
|
||||
if (mD > maxDiff) maxDiff = mD;
|
||||
|
||||
// use the first value:
|
||||
CSM(r, coord*numBones + b) = blok(0,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return maxDiff;
|
||||
}
|
||||
|
||||
// splits x_0, ... , x_dim coordinates in column vector 'L' into a numBones*(dimp1) x dim matrix 'Lsep';
|
||||
// assumes 'Lsep' has already been preallocated
|
||||
//
|
||||
// is this the same as uncolumnize? no.
|
||||
template <typename MatL, typename MatLsep>
|
||||
static void splitColumns(
|
||||
const MatL &L,
|
||||
int numBones,
|
||||
int dim,
|
||||
int dimp1,
|
||||
MatLsep &Lsep)
|
||||
{
|
||||
assert(L.cols() == 1);
|
||||
assert(L.rows() == dim*(dimp1)*numBones);
|
||||
|
||||
assert(Lsep.rows() == (dimp1)*numBones && Lsep.cols() == dim);
|
||||
|
||||
for (int b=0; b<numBones; b++)
|
||||
{
|
||||
for (int coord=0; coord<dimp1; coord++)
|
||||
{
|
||||
for (int c=0; c<dim; c++)
|
||||
{
|
||||
Lsep(coord*numBones + b, c) = L(coord*numBones*dim + c*numBones + b, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// the inverse of splitColumns, i.e., takes numBones*(dimp1) x dim matrix 'Lsep' and merges the dimensions
|
||||
// into columns vector 'L' (which is assumed to be already allocated):
|
||||
//
|
||||
// is this the same as columnize? no.
|
||||
template <typename MatrixXS>
|
||||
static void mergeColumns(const MatrixXS &Lsep, int numBones, int dim, int dimp1, MatrixXS &L)
|
||||
{
|
||||
assert(L.cols() == 1);
|
||||
assert(L.rows() == dim*(dimp1)*numBones);
|
||||
|
||||
assert(Lsep.rows() == (dimp1)*numBones && Lsep.cols() == dim);
|
||||
|
||||
for (int b=0; b<numBones; b++)
|
||||
{
|
||||
for (int coord=0; coord<dimp1; coord++)
|
||||
{
|
||||
for (int c=0; c<dim; c++)
|
||||
{
|
||||
L(coord*numBones*dim + c*numBones + b, 0) = Lsep(coord*numBones + b, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// converts "Solve1" the "rotations" part of FullSolve matrix (the first part)
|
||||
// into one "condensed" matrix CSolve1 while checking we're not losing any
|
||||
// information by this process; specifically, returns maximal difference from
|
||||
// scaled 3x3 identity blocks, which should be pretty small number
|
||||
template <typename MatrixXS>
|
||||
static typename MatrixXS::Scalar condense_Solve1(MatrixXS &Solve1, int numBones, int numGroups, int dim, MatrixXS &CSolve1)
|
||||
{
|
||||
assert(Solve1.rows() == dim*(dim + 1)*numBones);
|
||||
assert(Solve1.cols() == dim*dim*numGroups);
|
||||
|
||||
typedef typename MatrixXS::Scalar SSCALAR;
|
||||
SSCALAR maxDiff = 0.0f;
|
||||
|
||||
CSolve1.resize((dim + 1)*numBones, dim*numGroups);
|
||||
for (int rowCoord=0; rowCoord<dim+1; rowCoord++)
|
||||
{
|
||||
for (int b=0; b<numBones; b++)
|
||||
{
|
||||
for (int colCoord=0; colCoord<dim; colCoord++)
|
||||
{
|
||||
for (int g=0; g<numGroups; g++)
|
||||
{
|
||||
Eigen::Matrix3f blok;
|
||||
for (int r=0; r<3; r++)
|
||||
{
|
||||
for (int c=0; c<3; c++)
|
||||
{
|
||||
blok(r, c) = Solve1(rowCoord*numBones*dim + r*numBones + b, colCoord*numGroups*dim + c*numGroups + g);
|
||||
}
|
||||
}
|
||||
|
||||
SSCALAR mD = maxBlokErr<SSCALAR>(blok);
|
||||
if (mD > maxDiff) maxDiff = mD;
|
||||
|
||||
CSolve1(rowCoord*numBones + b, colCoord*numGroups + g) = blok(0,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return maxDiff;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename LbsMatrixType, typename SSCALAR>
|
||||
IGL_INLINE bool igl::arap_dof_recomputation(
|
||||
const Eigen::Matrix<int,Eigen::Dynamic,1> & fixed_dim,
|
||||
const Eigen::SparseMatrix<double> & A_eq,
|
||||
ArapDOFData<LbsMatrixType, SSCALAR> & data)
|
||||
{
|
||||
using namespace Eigen;
|
||||
typedef Matrix<SSCALAR, Dynamic, Dynamic> MatrixXS;
|
||||
|
||||
LbsMatrixType * Q;
|
||||
LbsMatrixType Qdyn;
|
||||
if(data.with_dynamics)
|
||||
{
|
||||
// multiply by 1/timestep and to quadratic coefficients matrix
|
||||
// Might be missing a 0.5 here
|
||||
LbsMatrixType Q_copy = data.Q;
|
||||
Qdyn = Q_copy + (1.0/(data.h*data.h))*data.Mass_tilde;
|
||||
Q = &Qdyn;
|
||||
|
||||
// This may/should be superfluous
|
||||
//printf("is_symmetric()\n");
|
||||
if(!is_symmetric(*Q))
|
||||
{
|
||||
//printf("Fixing symmetry...\n");
|
||||
// "Fix" symmetry
|
||||
LbsMatrixType QT = (*Q).transpose();
|
||||
LbsMatrixType Q_copy = *Q;
|
||||
*Q = 0.5*(Q_copy+QT);
|
||||
// Check that ^^^ this really worked. It doesn't always
|
||||
//assert(is_symmetric(*Q));
|
||||
}
|
||||
}else
|
||||
{
|
||||
Q = &data.Q;
|
||||
}
|
||||
|
||||
assert((int)data.CSM_M.size() == data.dim);
|
||||
assert(A_eq.cols() == data.m*data.dim*(data.dim+1));
|
||||
data.fixed_dim = fixed_dim;
|
||||
|
||||
if(fixed_dim.size() > 0)
|
||||
{
|
||||
assert(fixed_dim.maxCoeff() < data.m*data.dim*(data.dim+1));
|
||||
assert(fixed_dim.minCoeff() >= 0);
|
||||
}
|
||||
|
||||
#ifdef EXTREME_VERBOSE
|
||||
cout<<"data.fixed_dim=["<<endl<<data.fixed_dim<<endl<<"]+1;"<<endl;
|
||||
#endif
|
||||
|
||||
// Compute dense solve matrix (alternative of matrix factorization)
|
||||
//printf("kkt_inverse()\n");
|
||||
MatrixXd Qfull(*Q);
|
||||
MatrixXd A_eqfull(A_eq);
|
||||
MatrixXd M_Solve;
|
||||
|
||||
double timer0_start = get_seconds();
|
||||
bool use_lu = data.effective_dim != 2;
|
||||
//use_lu = false;
|
||||
//printf("use_lu: %s\n",(use_lu?"TRUE":"FALSE"));
|
||||
kkt_inverse(Qfull, A_eqfull, use_lu,M_Solve);
|
||||
double timer0_end = get_seconds();
|
||||
verbose("Bob timing: %.20f\n", (timer0_end - timer0_start)*1000.0);
|
||||
|
||||
// Precompute full solve matrix:
|
||||
const int fsRows = data.m * data.dim * (data.dim + 1); // 12 * number_of_bones
|
||||
const int fsCols1 = data.M_KG.cols(); // 9 * number_of_posConstraints
|
||||
const int fsCols2 = A_eq.rows(); // number_of_posConstraints
|
||||
data.M_FullSolve.resize(fsRows, fsCols1 + fsCols2);
|
||||
// note the magical multiplicative constant "-0.5", I've no idea why it has
|
||||
// to be there :)
|
||||
data.M_FullSolve <<
|
||||
(-0.5 * M_Solve.block(0, 0, fsRows, fsRows) * data.M_KG).template cast<SSCALAR>(),
|
||||
M_Solve.block(0, fsRows, fsRows, fsCols2).template cast<SSCALAR>();
|
||||
|
||||
if(data.with_dynamics)
|
||||
{
|
||||
printf(
|
||||
"---------------------------------------------------------------------\n"
|
||||
"\n\n\nWITH DYNAMICS recomputation\n\n\n"
|
||||
"---------------------------------------------------------------------\n"
|
||||
);
|
||||
// Also need to save Π1 before it gets multiplied by Ktilde (aka M_KG)
|
||||
data.Pi_1 = M_Solve.block(0, 0, fsRows, fsRows).template cast<SSCALAR>();
|
||||
}
|
||||
|
||||
// Precompute condensed matrices,
|
||||
// first CSM:
|
||||
std::vector<MatrixXS> CSM_M_SSCALAR;
|
||||
CSM_M_SSCALAR.resize(data.dim);
|
||||
for (int i=0; i<data.dim; i++) CSM_M_SSCALAR[i] = data.CSM_M[i].template cast<SSCALAR>();
|
||||
SSCALAR maxErr1 = condense_CSM(CSM_M_SSCALAR, data.m, data.dim, data.CSM);
|
||||
verbose("condense_CSM maxErr = %.15f (this should be close to zero)\n", maxErr1);
|
||||
assert(fabs(maxErr1) < 1e-5);
|
||||
|
||||
// and then solveBlock1:
|
||||
// number of groups
|
||||
const int k = data.CSM_M[0].rows()/data.dim;
|
||||
MatrixXS SolveBlock1 = data.M_FullSolve.block(0, 0, data.M_FullSolve.rows(), data.dim * data.dim * k);
|
||||
SSCALAR maxErr2 = condense_Solve1(SolveBlock1, data.m, k, data.dim, data.CSolveBlock1);
|
||||
verbose("condense_Solve1 maxErr = %.15f (this should be close to zero)\n", maxErr2);
|
||||
assert(fabs(maxErr2) < 1e-5);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename LbsMatrixType, typename SSCALAR>
|
||||
IGL_INLINE bool igl::arap_dof_update(
|
||||
const ArapDOFData<LbsMatrixType, SSCALAR> & data,
|
||||
const Eigen::Matrix<double,Eigen::Dynamic,1> & B_eq,
|
||||
const Eigen::MatrixXd & L0,
|
||||
const int max_iters,
|
||||
const double
|
||||
#ifdef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
|
||||
tol,
|
||||
#else
|
||||
/*tol*/,
|
||||
#endif
|
||||
Eigen::MatrixXd & L
|
||||
)
|
||||
{
|
||||
using namespace Eigen;
|
||||
typedef Matrix<SSCALAR, Dynamic, Dynamic> MatrixXS;
|
||||
#ifdef ARAP_GLOBAL_TIMING
|
||||
double timer_start = get_seconds();
|
||||
#endif
|
||||
|
||||
// number of dimensions
|
||||
assert((int)data.CSM_M.size() == data.dim);
|
||||
assert((int)L0.size() == (data.m)*data.dim*(data.dim+1));
|
||||
assert(max_iters >= 0);
|
||||
assert(tol >= 0);
|
||||
|
||||
// timing variables
|
||||
double
|
||||
sec_start,
|
||||
sec_covGather,
|
||||
sec_fitRotations,
|
||||
//sec_rhs,
|
||||
sec_prepMult,
|
||||
sec_solve, sec_end;
|
||||
|
||||
assert(L0.cols() == 1);
|
||||
#ifdef EXTREME_VERBOSE
|
||||
cout<<"dim="<<data.dim<<";"<<endl;
|
||||
cout<<"m="<<data.m<<";"<<endl;
|
||||
#endif
|
||||
|
||||
// number of groups
|
||||
const int k = data.CSM_M[0].rows()/data.dim;
|
||||
for(int i = 0;i<data.dim;i++)
|
||||
{
|
||||
assert(data.CSM_M[i].rows()/data.dim == k);
|
||||
}
|
||||
#ifdef EXTREME_VERBOSE
|
||||
cout<<"k="<<k<<";"<<endl;
|
||||
#endif
|
||||
|
||||
// resize output and initialize with initial guess
|
||||
L = L0;
|
||||
#ifndef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
|
||||
// Keep track of last solution
|
||||
MatrixXS L_prev;
|
||||
#endif
|
||||
// We will be iterating on L_SSCALAR, only at the end we convert back to double
|
||||
MatrixXS L_SSCALAR = L.cast<SSCALAR>();
|
||||
|
||||
int iters = 0;
|
||||
#ifndef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
|
||||
double max_diff = tol+1;
|
||||
#endif
|
||||
|
||||
MatrixXS S(k*data.dim,data.dim);
|
||||
MatrixXS R(data.dim,data.dim*k);
|
||||
Eigen::Matrix<SSCALAR,Eigen::Dynamic,1> Rcol(data.dim * data.dim * k);
|
||||
Matrix<SSCALAR,Dynamic,1> B_eq_SSCALAR = B_eq.cast<SSCALAR>();
|
||||
Matrix<SSCALAR,Dynamic,1> B_eq_fix_SSCALAR;
|
||||
Matrix<SSCALAR,Dynamic,1> L0SSCALAR = L0.cast<SSCALAR>();
|
||||
slice(L0SSCALAR, data.fixed_dim, B_eq_fix_SSCALAR);
|
||||
//MatrixXS rhsFull(Rcol.rows() + B_eq.rows() + B_eq_fix_SSCALAR.rows(), 1);
|
||||
|
||||
MatrixXS Lsep(data.m*(data.dim + 1), 3);
|
||||
const MatrixXS L_part2 =
|
||||
data.M_FullSolve.block(0, Rcol.rows(), data.M_FullSolve.rows(), B_eq_SSCALAR.rows()) * B_eq_SSCALAR;
|
||||
const MatrixXS L_part3 =
|
||||
data.M_FullSolve.block(0, Rcol.rows() + B_eq_SSCALAR.rows(), data.M_FullSolve.rows(), B_eq_fix_SSCALAR.rows()) * B_eq_fix_SSCALAR;
|
||||
MatrixXS L_part2and3 = L_part2 + L_part3;
|
||||
|
||||
// preallocate workspace variables:
|
||||
MatrixXS Rxyz(k*data.dim, data.dim);
|
||||
MatrixXS L_part1xyz((data.dim + 1) * data.m, data.dim);
|
||||
MatrixXS L_part1(data.dim * (data.dim + 1) * data.m, 1);
|
||||
|
||||
#ifdef ARAP_GLOBAL_TIMING
|
||||
double timer_prepFinished = get_seconds();
|
||||
#endif
|
||||
|
||||
#ifdef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
|
||||
while(iters < max_iters)
|
||||
#else
|
||||
while(iters < max_iters && max_diff > tol)
|
||||
#endif
|
||||
{
|
||||
if(data.print_timings)
|
||||
{
|
||||
sec_start = get_seconds();
|
||||
}
|
||||
|
||||
#ifndef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
|
||||
L_prev = L_SSCALAR;
|
||||
#endif
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Local step: Fix positions, fit rotations
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Gather covariance matrices
|
||||
|
||||
splitColumns(L_SSCALAR, data.m, data.dim, data.dim + 1, Lsep);
|
||||
|
||||
S = data.CSM * Lsep;
|
||||
// interestingly, this doesn't seem to be so slow, but
|
||||
//MKL is still 2x faster (probably due to AVX)
|
||||
//#ifdef IGL_ARAP_DOF_DOUBLE_PRECISION_SOLVE
|
||||
// MKL_matMatMult_double(S, data.CSM, Lsep);
|
||||
//#else
|
||||
// MKL_matMatMult_single(S, data.CSM, Lsep);
|
||||
//#endif
|
||||
|
||||
if(data.print_timings)
|
||||
{
|
||||
sec_covGather = get_seconds();
|
||||
}
|
||||
|
||||
#ifdef EXTREME_VERBOSE
|
||||
cout<<"S=["<<endl<<S<<endl<<"];"<<endl;
|
||||
#endif
|
||||
// Fit rotations to covariance matrices
|
||||
if(data.effective_dim == 2)
|
||||
{
|
||||
fit_rotations_planar(S,R);
|
||||
}else
|
||||
{
|
||||
#ifdef __SSE__ // fit_rotations_SSE will convert to float if necessary
|
||||
fit_rotations_SSE(S,R);
|
||||
#else
|
||||
fit_rotations(S,false,R);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef EXTREME_VERBOSE
|
||||
cout<<"R=["<<endl<<R<<endl<<"];"<<endl;
|
||||
#endif
|
||||
|
||||
if(data.print_timings)
|
||||
{
|
||||
sec_fitRotations = get_seconds();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// "Global" step: fix rotations per mesh vertex, solve for
|
||||
// linear transformations at handles
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// all this shuffling is retarded and not completely negligible time-wise;
|
||||
// TODO: change fit_rotations_XXX so it returns R in the format ready for
|
||||
// CSolveBlock1 multiplication
|
||||
columnize(R, k, 2, Rcol);
|
||||
#ifdef EXTREME_VERBOSE
|
||||
cout<<"Rcol=["<<endl<<Rcol<<endl<<"];"<<endl;
|
||||
#endif
|
||||
splitColumns(Rcol, k, data.dim, data.dim, Rxyz);
|
||||
|
||||
if(data.print_timings)
|
||||
{
|
||||
sec_prepMult = get_seconds();
|
||||
}
|
||||
|
||||
L_part1xyz = data.CSolveBlock1 * Rxyz;
|
||||
//#ifdef IGL_ARAP_DOF_DOUBLE_PRECISION_SOLVE
|
||||
// MKL_matMatMult_double(L_part1xyz, data.CSolveBlock1, Rxyz);
|
||||
//#else
|
||||
// MKL_matMatMult_single(L_part1xyz, data.CSolveBlock1, Rxyz);
|
||||
//#endif
|
||||
mergeColumns(L_part1xyz, data.m, data.dim, data.dim + 1, L_part1);
|
||||
|
||||
if(data.with_dynamics)
|
||||
{
|
||||
// Consider reordering or precomputing matrix multiplications
|
||||
MatrixXS L_part1_dyn(data.dim * (data.dim + 1) * data.m, 1);
|
||||
// Eigen can't parse this:
|
||||
//L_part1_dyn =
|
||||
// -(2.0/(data.h*data.h)) * data.Pi_1 * data.Mass_tilde * data.L0 +
|
||||
// (1.0/(data.h*data.h)) * data.Pi_1 * data.Mass_tilde * data.Lm1;
|
||||
// -1.0 because we've moved these linear terms to the right hand side
|
||||
//MatrixXS temp = -1.0 *
|
||||
// ((-2.0/(data.h*data.h)) * data.L0.array() +
|
||||
// (1.0/(data.h*data.h)) * data.Lm1.array()).matrix();
|
||||
//MatrixXS temp = -1.0 *
|
||||
// ( (-1.0/(data.h*data.h)) * data.L0.array() +
|
||||
// (1.0/(data.h*data.h)) * data.Lm1.array()
|
||||
// (-1.0/(data.h*data.h)) * data.L0.array() +
|
||||
// ).matrix();
|
||||
//Lvel0 = (1.0/(data.h)) * data.Lm1.array() - data.L0.array();
|
||||
MatrixXS temp = -1.0 *
|
||||
( (-1.0/(data.h*data.h)) * data.L0.array() +
|
||||
(1.0/(data.h)) * data.Lvel0.array()
|
||||
).matrix();
|
||||
MatrixXd temp_d = temp.template cast<double>();
|
||||
|
||||
MatrixXd temp_g = data.fgrav*(data.grav_mag*data.grav_dir);
|
||||
|
||||
assert(data.fext.rows() == temp_g.rows());
|
||||
assert(data.fext.cols() == temp_g.cols());
|
||||
MatrixXd temp2 = data.Mass_tilde * temp_d + temp_g + data.fext.template cast<double>();
|
||||
MatrixXS temp2_f = temp2.template cast<SSCALAR>();
|
||||
L_part1_dyn = data.Pi_1 * temp2_f;
|
||||
L_part1.array() = L_part1.array() + L_part1_dyn.array();
|
||||
}
|
||||
|
||||
//L_SSCALAR = L_part1 + L_part2and3;
|
||||
assert(L_SSCALAR.rows() == L_part1.rows() && L_SSCALAR.rows() == L_part2and3.rows());
|
||||
for (int i=0; i<L_SSCALAR.rows(); i++)
|
||||
{
|
||||
L_SSCALAR(i, 0) = L_part1(i, 0) + L_part2and3(i, 0);
|
||||
}
|
||||
|
||||
#ifdef EXTREME_VERBOSE
|
||||
cout<<"L=["<<endl<<L<<endl<<"];"<<endl;
|
||||
#endif
|
||||
|
||||
if(data.print_timings)
|
||||
{
|
||||
sec_solve = get_seconds();
|
||||
}
|
||||
|
||||
#ifndef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
|
||||
// Compute maximum absolute difference with last iteration's solution
|
||||
max_diff = (L_SSCALAR-L_prev).eval().array().abs().matrix().maxCoeff();
|
||||
#endif
|
||||
iters++;
|
||||
|
||||
if(data.print_timings)
|
||||
{
|
||||
sec_end = get_seconds();
|
||||
#ifndef WIN32
|
||||
// trick to get sec_* variables to compile without warning on mac
|
||||
if(false)
|
||||
#endif
|
||||
printf(
|
||||
"\ntotal iteration time = %f "
|
||||
"[local: covGather = %f, "
|
||||
"fitRotations = %f, "
|
||||
"global: prep = %f, "
|
||||
"solve = %f, "
|
||||
"error = %f [ms]]\n",
|
||||
(sec_end - sec_start)*1000.0,
|
||||
(sec_covGather - sec_start)*1000.0,
|
||||
(sec_fitRotations - sec_covGather)*1000.0,
|
||||
(sec_prepMult - sec_fitRotations)*1000.0,
|
||||
(sec_solve - sec_prepMult)*1000.0,
|
||||
(sec_end - sec_solve)*1000.0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
L = L_SSCALAR.template cast<double>();
|
||||
assert(L.cols() == 1);
|
||||
|
||||
#ifdef ARAP_GLOBAL_TIMING
|
||||
double timer_finito = get_seconds();
|
||||
printf(
|
||||
"ARAP preparation = %f, "
|
||||
"all %i iterations = %f [ms]\n",
|
||||
(timer_prepFinished - timer_start)*1000.0,
|
||||
max_iters,
|
||||
(timer_finito - timer_prepFinished)*1000.0);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template bool igl::arap_dof_update<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double>(ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double> const&, Eigen::Matrix<double, -1, 1, 0, -1, 1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, int, double, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
|
||||
template bool igl::arap_dof_recomputation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double>(Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::SparseMatrix<double, 0, int> const&, ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double>&);
|
||||
template bool igl::arap_dof_precomputation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double>&);
|
||||
template bool igl::arap_dof_update<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float>(igl::ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float> const&, Eigen::Matrix<double, -1, 1, 0, -1, 1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, int, double, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
|
||||
template bool igl::arap_dof_recomputation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float>(Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::SparseMatrix<double, 0, int> const&, igl::ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float>&);
|
||||
template bool igl::arap_dof_precomputation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, igl::ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float>&);
|
||||
#endif
|
||||
@@ -1,259 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "arap_linear_block.h"
|
||||
#include "verbose.h"
|
||||
#include "cotmatrix_entries.h"
|
||||
#include <Eigen/Dense>
|
||||
|
||||
template <typename MatV, typename MatF, typename MatK>
|
||||
IGL_INLINE void igl::arap_linear_block(
|
||||
const MatV & V,
|
||||
const MatF & F,
|
||||
const int d,
|
||||
const igl::ARAPEnergyType energy,
|
||||
MatK & Kd)
|
||||
{
|
||||
switch(energy)
|
||||
{
|
||||
case ARAP_ENERGY_TYPE_SPOKES:
|
||||
return igl::arap_linear_block_spokes(V,F,d,Kd);
|
||||
break;
|
||||
case ARAP_ENERGY_TYPE_SPOKES_AND_RIMS:
|
||||
return igl::arap_linear_block_spokes_and_rims(V,F,d,Kd);
|
||||
break;
|
||||
case ARAP_ENERGY_TYPE_ELEMENTS:
|
||||
return igl::arap_linear_block_elements(V,F,d,Kd);
|
||||
break;
|
||||
default:
|
||||
verbose("Unsupported energy type: %d\n",energy);
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename MatV, typename MatF, typename MatK>
|
||||
IGL_INLINE void igl::arap_linear_block_spokes(
|
||||
const MatV & V,
|
||||
const MatF & F,
|
||||
const int d,
|
||||
MatK & Kd)
|
||||
{
|
||||
typedef typename MatK::Scalar Scalar;
|
||||
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
// simplex size (3: triangles, 4: tetrahedra)
|
||||
int simplex_size = F.cols();
|
||||
// Number of elements
|
||||
int m = F.rows();
|
||||
// Temporary output
|
||||
Matrix<int,Dynamic,2> edges;
|
||||
Kd.resize(V.rows(), V.rows());
|
||||
vector<Triplet<Scalar> > Kd_IJV;
|
||||
if(simplex_size == 3)
|
||||
{
|
||||
// triangles
|
||||
Kd.reserve(7*V.rows());
|
||||
Kd_IJV.reserve(7*V.rows());
|
||||
edges.resize(3,2);
|
||||
edges <<
|
||||
1,2,
|
||||
2,0,
|
||||
0,1;
|
||||
}else if(simplex_size == 4)
|
||||
{
|
||||
// tets
|
||||
Kd.reserve(17*V.rows());
|
||||
Kd_IJV.reserve(17*V.rows());
|
||||
edges.resize(6,2);
|
||||
edges <<
|
||||
1,2,
|
||||
2,0,
|
||||
0,1,
|
||||
3,0,
|
||||
3,1,
|
||||
3,2;
|
||||
}
|
||||
// gather cotangent weights
|
||||
Matrix<Scalar,Dynamic,Dynamic> C;
|
||||
cotmatrix_entries(V,F,C);
|
||||
// should have weights for each edge
|
||||
assert(C.cols() == edges.rows());
|
||||
// loop over elements
|
||||
for(int i = 0;i<m;i++)
|
||||
{
|
||||
// loop over edges of element
|
||||
for(int e = 0;e<edges.rows();e++)
|
||||
{
|
||||
int source = F(i,edges(e,0));
|
||||
int dest = F(i,edges(e,1));
|
||||
double v = 0.5*C(i,e)*(V(source,d)-V(dest,d));
|
||||
Kd_IJV.push_back(Triplet<Scalar>(source,dest,v));
|
||||
Kd_IJV.push_back(Triplet<Scalar>(dest,source,-v));
|
||||
Kd_IJV.push_back(Triplet<Scalar>(source,source,v));
|
||||
Kd_IJV.push_back(Triplet<Scalar>(dest,dest,-v));
|
||||
}
|
||||
}
|
||||
Kd.setFromTriplets(Kd_IJV.begin(),Kd_IJV.end());
|
||||
Kd.makeCompressed();
|
||||
}
|
||||
|
||||
template <typename MatV, typename MatF, typename MatK>
|
||||
IGL_INLINE void igl::arap_linear_block_spokes_and_rims(
|
||||
const MatV & V,
|
||||
const MatF & F,
|
||||
const int d,
|
||||
MatK & Kd)
|
||||
{
|
||||
typedef typename MatK::Scalar Scalar;
|
||||
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
// simplex size (3: triangles, 4: tetrahedra)
|
||||
int simplex_size = F.cols();
|
||||
// Number of elements
|
||||
int m = F.rows();
|
||||
// Temporary output
|
||||
Kd.resize(V.rows(), V.rows());
|
||||
vector<Triplet<Scalar> > Kd_IJV;
|
||||
Matrix<int,Dynamic,2> edges;
|
||||
if(simplex_size == 3)
|
||||
{
|
||||
// triangles
|
||||
Kd.reserve(7*V.rows());
|
||||
Kd_IJV.reserve(7*V.rows());
|
||||
edges.resize(3,2);
|
||||
edges <<
|
||||
1,2,
|
||||
2,0,
|
||||
0,1;
|
||||
}else if(simplex_size == 4)
|
||||
{
|
||||
// tets
|
||||
Kd.reserve(17*V.rows());
|
||||
Kd_IJV.reserve(17*V.rows());
|
||||
edges.resize(6,2);
|
||||
edges <<
|
||||
1,2,
|
||||
2,0,
|
||||
0,1,
|
||||
3,0,
|
||||
3,1,
|
||||
3,2;
|
||||
// Not implemented yet for tets
|
||||
assert(false);
|
||||
}
|
||||
// gather cotangent weights
|
||||
Matrix<Scalar,Dynamic,Dynamic> C;
|
||||
cotmatrix_entries(V,F,C);
|
||||
// should have weights for each edge
|
||||
assert(C.cols() == edges.rows());
|
||||
// loop over elements
|
||||
for(int i = 0;i<m;i++)
|
||||
{
|
||||
// loop over edges of element
|
||||
for(int e = 0;e<edges.rows();e++)
|
||||
{
|
||||
int source = F(i,edges(e,0));
|
||||
int dest = F(i,edges(e,1));
|
||||
double v = C(i,e)*(V(source,d)-V(dest,d))/3.0;
|
||||
// loop over edges again
|
||||
for(int f = 0;f<edges.rows();f++)
|
||||
{
|
||||
int Rs = F(i,edges(f,0));
|
||||
int Rd = F(i,edges(f,1));
|
||||
if(Rs == source && Rd == dest)
|
||||
{
|
||||
Kd_IJV.push_back(Triplet<Scalar>(Rs,Rd,v));
|
||||
Kd_IJV.push_back(Triplet<Scalar>(Rd,Rs,-v));
|
||||
}else if(Rd == source)
|
||||
{
|
||||
Kd_IJV.push_back(Triplet<Scalar>(Rd,Rs,v));
|
||||
}else if(Rs == dest)
|
||||
{
|
||||
Kd_IJV.push_back(Triplet<Scalar>(Rs,Rd,-v));
|
||||
}
|
||||
}
|
||||
Kd_IJV.push_back(Triplet<Scalar>(source,source,v));
|
||||
Kd_IJV.push_back(Triplet<Scalar>(dest,dest,-v));
|
||||
}
|
||||
}
|
||||
Kd.setFromTriplets(Kd_IJV.begin(),Kd_IJV.end());
|
||||
Kd.makeCompressed();
|
||||
}
|
||||
|
||||
template <typename MatV, typename MatF, typename MatK>
|
||||
IGL_INLINE void igl::arap_linear_block_elements(
|
||||
const MatV & V,
|
||||
const MatF & F,
|
||||
const int d,
|
||||
MatK & Kd)
|
||||
{
|
||||
typedef typename MatK::Scalar Scalar;
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
// simplex size (3: triangles, 4: tetrahedra)
|
||||
int simplex_size = F.cols();
|
||||
// Number of elements
|
||||
int m = F.rows();
|
||||
// Temporary output
|
||||
Kd.resize(V.rows(), F.rows());
|
||||
vector<Triplet<Scalar> > Kd_IJV;
|
||||
Matrix<int,Dynamic,2> edges;
|
||||
if(simplex_size == 3)
|
||||
{
|
||||
// triangles
|
||||
Kd.reserve(7*V.rows());
|
||||
Kd_IJV.reserve(7*V.rows());
|
||||
edges.resize(3,2);
|
||||
edges <<
|
||||
1,2,
|
||||
2,0,
|
||||
0,1;
|
||||
}else if(simplex_size == 4)
|
||||
{
|
||||
// tets
|
||||
Kd.reserve(17*V.rows());
|
||||
Kd_IJV.reserve(17*V.rows());
|
||||
edges.resize(6,2);
|
||||
edges <<
|
||||
1,2,
|
||||
2,0,
|
||||
0,1,
|
||||
3,0,
|
||||
3,1,
|
||||
3,2;
|
||||
}
|
||||
// gather cotangent weights
|
||||
Matrix<Scalar,Dynamic,Dynamic> C;
|
||||
cotmatrix_entries(V,F,C);
|
||||
// should have weights for each edge
|
||||
assert(C.cols() == edges.rows());
|
||||
// loop over elements
|
||||
for(int i = 0;i<m;i++)
|
||||
{
|
||||
// loop over edges of element
|
||||
for(int e = 0;e<edges.rows();e++)
|
||||
{
|
||||
int source = F(i,edges(e,0));
|
||||
int dest = F(i,edges(e,1));
|
||||
double v = C(i,e)*(V(source,d)-V(dest,d));
|
||||
Kd_IJV.push_back(Triplet<Scalar>(source,i,v));
|
||||
Kd_IJV.push_back(Triplet<Scalar>(dest,i,-v));
|
||||
}
|
||||
}
|
||||
Kd.setFromTriplets(Kd_IJV.begin(),Kd_IJV.end());
|
||||
Kd.makeCompressed();
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::arap_linear_block<Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >, Eigen::SparseMatrix<double, 0, int> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, igl::ARAPEnergyType, Eigen::SparseMatrix<double, 0, int>&);
|
||||
template void igl::arap_linear_block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::SparseMatrix<double, 0, int> >(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, int, igl::ARAPEnergyType, Eigen::SparseMatrix<double, 0, int>&);
|
||||
#endif
|
||||
@@ -1,95 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "arap_rhs.h"
|
||||
#include "arap_linear_block.h"
|
||||
#include "verbose.h"
|
||||
#include "repdiag.h"
|
||||
#include "cat.h"
|
||||
#include <iostream>
|
||||
|
||||
template<typename DerivedV, typename DerivedF, typename DerivedK>
|
||||
IGL_INLINE void igl::arap_rhs(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const int dim,
|
||||
const igl::ARAPEnergyType energy,
|
||||
Eigen::SparseCompressedBase<DerivedK>& K)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
// Number of dimensions
|
||||
int Vdim = V.cols();
|
||||
//// Number of mesh vertices
|
||||
//int n = V.rows();
|
||||
//// Number of mesh elements
|
||||
//int m = F.rows();
|
||||
//// number of rotations
|
||||
//int nr;
|
||||
switch(energy)
|
||||
{
|
||||
case ARAP_ENERGY_TYPE_SPOKES:
|
||||
//nr = n;
|
||||
break;
|
||||
case ARAP_ENERGY_TYPE_SPOKES_AND_RIMS:
|
||||
//nr = n;
|
||||
break;
|
||||
case ARAP_ENERGY_TYPE_ELEMENTS:
|
||||
//nr = m;
|
||||
break;
|
||||
default:
|
||||
fprintf(
|
||||
stderr,
|
||||
"arap_rhs.h: Error: Unsupported arap energy %d\n",
|
||||
energy);
|
||||
return;
|
||||
}
|
||||
|
||||
DerivedK KX,KY,KZ;
|
||||
arap_linear_block(V,F,0,energy,KX);
|
||||
arap_linear_block(V,F,1,energy,KY);
|
||||
if(Vdim == 2)
|
||||
{
|
||||
K = cat(2,repdiag(KX,dim),repdiag(KY,dim));
|
||||
}else if(Vdim == 3)
|
||||
{
|
||||
arap_linear_block(V,F,2,energy,KZ);
|
||||
if(dim == 3)
|
||||
{
|
||||
K = cat(2,cat(2,repdiag(KX,dim),repdiag(KY,dim)),repdiag(KZ,dim));
|
||||
}else if(dim ==2)
|
||||
{
|
||||
DerivedK ZZ(KX.rows()*2,KX.cols());
|
||||
K = cat(2,cat(2,
|
||||
cat(2,repdiag(KX,dim),ZZ),
|
||||
cat(2,repdiag(KY,dim),ZZ)),
|
||||
cat(2,repdiag(KZ,dim),ZZ));
|
||||
}else
|
||||
{
|
||||
assert(false);
|
||||
fprintf(
|
||||
stderr,
|
||||
"arap_rhs.h: Error: Unsupported dimension %d\n",
|
||||
dim);
|
||||
}
|
||||
}else
|
||||
{
|
||||
assert(false);
|
||||
fprintf(
|
||||
stderr,
|
||||
"arap_rhs.h: Error: Unsupported dimension %d\n",
|
||||
Vdim);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
template void igl::arap_rhs(const Eigen::MatrixBase<Eigen::MatrixXd> & V, const Eigen::MatrixBase<Eigen::MatrixXi> & F,const int dim, const igl::ARAPEnergyType energy,Eigen::SparseCompressedBase<Eigen::SparseMatrix<double>>& K);
|
||||
#endif
|
||||
@@ -1,69 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// 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 "average_from_edges_onto_vertices.h"
|
||||
|
||||
template<typename DerivedF,typename DerivedE,typename DerivedoE,
|
||||
typename DeriveduE,typename DeriveduV>
|
||||
IGL_INLINE void
|
||||
igl::average_from_edges_onto_vertices(
|
||||
const Eigen::MatrixBase<DerivedF> &F,
|
||||
const Eigen::MatrixBase<DerivedE> &E,
|
||||
const Eigen::MatrixBase<DerivedoE> &oE,
|
||||
const Eigen::MatrixBase<DeriveduE> &uE,
|
||||
Eigen::PlainObjectBase<DeriveduV> &uV)
|
||||
{
|
||||
using Scalar = typename DeriveduE::Scalar;
|
||||
using VecX = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
|
||||
using Int = typename DerivedF::Scalar;
|
||||
|
||||
assert(E.rows()==F.rows() && "E does not match dimensions of F.");
|
||||
assert(oE.rows()==F.rows() && "oE does not match dimensions of F.");
|
||||
assert(E.cols()==3 && F.cols()==3 && oE.cols()==3 &&
|
||||
"This method is for triangle meshes.");
|
||||
|
||||
const Int n = F.maxCoeff()+1;
|
||||
|
||||
VecX edgesPerVertex(n);
|
||||
edgesPerVertex.setZero();
|
||||
uV.resize(n,1);
|
||||
uV.setZero();
|
||||
|
||||
for(Eigen::Index i=0; i<F.rows(); ++i) {
|
||||
for(int j=0; j<3; ++j) {
|
||||
if(oE(i,j)<0) {
|
||||
continue;
|
||||
}
|
||||
const Int e = E(i,j);
|
||||
const Int vi=F(i,(j+1)%3), vj=F(i,(j+2)%3);
|
||||
|
||||
//Count vertex valence
|
||||
++edgesPerVertex(vi);
|
||||
++edgesPerVertex(vj);
|
||||
|
||||
//Average uE value onto vertices
|
||||
uV(vi) += uE(e);
|
||||
uV(vj) += uE(e);
|
||||
}
|
||||
}
|
||||
|
||||
//Divide by valence
|
||||
for(Int i=0; i<n; ++i) {
|
||||
const Scalar valence = edgesPerVertex(i);
|
||||
if(valence>0) {
|
||||
uV(i) /= valence;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::average_from_edges_onto_vertices<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>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::average_from_edges_onto_vertices<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>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::average_from_edges_onto_vertices<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>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
@@ -1,27 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "average_onto_faces.h"
|
||||
|
||||
template <typename DerivedF, typename DerivedS, typename DerivedSF>
|
||||
IGL_INLINE void igl::average_onto_faces(
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const Eigen::MatrixBase<DerivedS> & S,
|
||||
Eigen::PlainObjectBase<DerivedSF> & SF)
|
||||
{
|
||||
SF.setConstant(F.rows(),S.cols(),0);
|
||||
for (int i = 0; i <F.rows(); ++i)
|
||||
for (int j = 0; j<F.cols(); ++j)
|
||||
SF.row(i) += S.row(F(i,j));
|
||||
SF.array() /= F.cols();
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::average_onto_faces<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
@@ -1,33 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "average_onto_vertices.h"
|
||||
|
||||
template<typename DerivedV,typename DerivedF,typename DerivedS,typename DerivedSV >
|
||||
IGL_INLINE void igl::average_onto_vertices(const Eigen::MatrixBase<DerivedV> &V,
|
||||
const Eigen::MatrixBase<DerivedF> &F,
|
||||
const Eigen::MatrixBase<DerivedS> &S,
|
||||
Eigen::PlainObjectBase<DerivedSV> &SV)
|
||||
{
|
||||
SV = DerivedS::Zero(V.rows(),S.cols());
|
||||
Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,1> COUNT(V.rows());
|
||||
COUNT.setZero();
|
||||
for (int i = 0; i <F.rows(); ++i)
|
||||
{
|
||||
for (int j = 0; j<F.cols(); ++j)
|
||||
{
|
||||
SV.row(F(i,j)) += S.row(i);
|
||||
COUNT[F(i,j)] ++;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i <V.rows(); ++i)
|
||||
SV.row(i) /= COUNT[i];
|
||||
};
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
#endif
|
||||
@@ -1,39 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "avg_edge_length.h"
|
||||
#include "edges.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
template <typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE double igl::avg_edge_length(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F)
|
||||
{
|
||||
typedef typename DerivedF::Scalar Index;
|
||||
Eigen::Matrix<Index, Eigen::Dynamic, 2> E;
|
||||
|
||||
igl::edges(F, E);
|
||||
|
||||
double avg = 0;
|
||||
|
||||
for (unsigned i=0;i<E.rows();++i)
|
||||
{
|
||||
avg += (V.row(E(i,0)) - V.row(E(i,1))).norm();
|
||||
}
|
||||
|
||||
return avg / (double) E.rows();
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template double igl::avg_edge_length<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
|
||||
template double igl::avg_edge_length<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&);
|
||||
// generated by autoexplicit.sh
|
||||
#endif
|
||||
@@ -1,42 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "axis_angle_to_quat.h"
|
||||
#include "EPS.h"
|
||||
#include <cmath>
|
||||
|
||||
// http://www.antisphere.com/Wiki/tools:anttweakbar
|
||||
template <typename Q_type>
|
||||
IGL_INLINE void igl::axis_angle_to_quat(
|
||||
const Q_type *axis,
|
||||
const Q_type angle,
|
||||
Q_type *out)
|
||||
{
|
||||
Q_type n = axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2];
|
||||
if( fabs(n)>igl::EPS<Q_type>())
|
||||
{
|
||||
Q_type f = 0.5*angle;
|
||||
out[3] = cos(f);
|
||||
f = sin(f)/sqrt(n);
|
||||
out[0] = axis[0]*f;
|
||||
out[1] = axis[1]*f;
|
||||
out[2] = axis[2]*f;
|
||||
}
|
||||
else
|
||||
{
|
||||
out[3] = 1.0;
|
||||
out[0] = out[1] = out[2] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::axis_angle_to_quat<double>(double const*, double, double*);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::axis_angle_to_quat<float>(float const*, float, float*);
|
||||
#endif
|
||||
@@ -1,58 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "barycenter.h"
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedBC>
|
||||
IGL_INLINE void igl::barycenter(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedBC> & BC)
|
||||
{
|
||||
BC.setZero(F.rows(),V.cols());
|
||||
// Loop over faces
|
||||
for(int i = 0;i<F.rows();i++)
|
||||
{
|
||||
// loop around face
|
||||
for(int j = 0;j<F.cols();j++)
|
||||
{
|
||||
// Accumulate
|
||||
BC.row(i) += V.row(F(i,j));
|
||||
}
|
||||
// average
|
||||
BC.row(i) /= double(F.cols());
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::barycenter<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::barycenter<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::barycenter<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::barycenter<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 4, 0, -1, 4> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> >&);
|
||||
template void igl::barycenter<Eigen::Matrix<double, -1, 4, 0, -1, 4>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 4, 0, -1, 4> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> >&);
|
||||
template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::barycenter<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::barycenter<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
|
||||
template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 2, 3, 0, 2, 3>, Eigen::Matrix<double, 2, 3, 0, 2, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 2, 3, 0, 2, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 3, 0, 2, 3> >&);
|
||||
template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 2, 3, 0, 2, 3>, Eigen::Matrix<double, 2, 3, 0, 2, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 2, 3, 0, 2, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 3, 0, 2, 3> >&);
|
||||
template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
|
||||
template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
#endif
|
||||
@@ -1,113 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 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 "barycentric_coordinates.h"
|
||||
#include "volume.h"
|
||||
|
||||
template <
|
||||
typename DerivedP,
|
||||
typename DerivedA,
|
||||
typename DerivedB,
|
||||
typename DerivedC,
|
||||
typename DerivedD,
|
||||
typename DerivedL>
|
||||
IGL_INLINE void igl::barycentric_coordinates(
|
||||
const Eigen::MatrixBase<DerivedP> & P,
|
||||
const Eigen::MatrixBase<DerivedA> & A,
|
||||
const Eigen::MatrixBase<DerivedB> & B,
|
||||
const Eigen::MatrixBase<DerivedC> & C,
|
||||
const Eigen::MatrixBase<DerivedD> & D,
|
||||
Eigen::PlainObjectBase<DerivedL> & L)
|
||||
{
|
||||
using namespace Eigen;
|
||||
assert(P.cols() == 3 && "query must be in 3d");
|
||||
assert(A.cols() == 3 && "corners must be in 3d");
|
||||
assert(B.cols() == 3 && "corners must be in 3d");
|
||||
assert(C.cols() == 3 && "corners must be in 3d");
|
||||
assert(D.cols() == 3 && "corners must be in 3d");
|
||||
assert(P.rows() == A.rows() && "Must have same number of queries as corners");
|
||||
assert(A.rows() == B.rows() && "Corners must be same size");
|
||||
assert(A.rows() == C.rows() && "Corners must be same size");
|
||||
assert(A.rows() == D.rows() && "Corners must be same size");
|
||||
typedef Matrix<typename DerivedL::Scalar,DerivedL::RowsAtCompileTime,1>
|
||||
VectorXS;
|
||||
// Total volume
|
||||
VectorXS vol,LA,LB,LC,LD;
|
||||
volume(B,D,C,P,LA);
|
||||
volume(A,C,D,P,LB);
|
||||
volume(A,D,B,P,LC);
|
||||
volume(A,B,C,P,LD);
|
||||
volume(A,B,C,D,vol);
|
||||
L.resize(P.rows(),4);
|
||||
L<<LA,LB,LC,LD;
|
||||
L.array().colwise() /= vol.array();
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedP,
|
||||
typename DerivedA,
|
||||
typename DerivedB,
|
||||
typename DerivedC,
|
||||
typename DerivedL>
|
||||
IGL_INLINE void igl::barycentric_coordinates(
|
||||
const Eigen::MatrixBase<DerivedP> & P,
|
||||
const Eigen::MatrixBase<DerivedA> & A,
|
||||
const Eigen::MatrixBase<DerivedB> & B,
|
||||
const Eigen::MatrixBase<DerivedC> & C,
|
||||
Eigen::PlainObjectBase<DerivedL> & L)
|
||||
{
|
||||
using namespace Eigen;
|
||||
#ifndef NDEBUG
|
||||
const int DIM = P.cols();
|
||||
assert(A.cols() == DIM && "corners must be in same dimension as query");
|
||||
assert(B.cols() == DIM && "corners must be in same dimension as query");
|
||||
assert(C.cols() == DIM && "corners must be in same dimension as query");
|
||||
assert(P.rows() == A.rows() && "Must have same number of queries as corners");
|
||||
assert(A.rows() == B.rows() && "Corners must be same size");
|
||||
assert(A.rows() == C.rows() && "Corners must be same size");
|
||||
#endif
|
||||
|
||||
// http://gamedev.stackexchange.com/a/23745
|
||||
typedef
|
||||
Eigen::Array<
|
||||
typename DerivedP::Scalar,
|
||||
DerivedP::RowsAtCompileTime,
|
||||
DerivedP::ColsAtCompileTime>
|
||||
ArrayS;
|
||||
typedef
|
||||
Eigen::Array<
|
||||
typename DerivedP::Scalar,
|
||||
DerivedP::RowsAtCompileTime,
|
||||
1>
|
||||
VectorS;
|
||||
|
||||
const ArrayS v0 = B.array() - A.array();
|
||||
const ArrayS v1 = C.array() - A.array();
|
||||
const ArrayS v2 = P.array() - A.array();
|
||||
VectorS d00 = (v0*v0).rowwise().sum();
|
||||
VectorS d01 = (v0*v1).rowwise().sum();
|
||||
VectorS d11 = (v1*v1).rowwise().sum();
|
||||
VectorS d20 = (v2*v0).rowwise().sum();
|
||||
VectorS d21 = (v2*v1).rowwise().sum();
|
||||
VectorS denom = d00 * d11 - d01 * d01;
|
||||
L.resize(P.rows(),3);
|
||||
L.col(1) = (d11 * d20 - d01 * d21) / denom;
|
||||
L.col(2) = (d00 * d21 - d01 * d20) / denom;
|
||||
L.col(0) = 1.0f -(L.col(1) + L.col(2)).array();
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::barycentric_coordinates<Eigen::Matrix<float, 1, -1, 1, 1, -1>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, 1, -1, 1, 1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&);
|
||||
template void igl::barycentric_coordinates<Eigen::Matrix<double, 1, -1, 1, 1, -1>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
|
||||
template void igl::barycentric_coordinates<Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&);
|
||||
template void igl::barycentric_coordinates<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::barycentric_coordinates<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
|
||||
template void igl::barycentric_coordinates<Eigen::Matrix<double, 1, 2, 1, 1, 2>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
|
||||
template void igl::barycentric_coordinates<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
|
||||
template void igl::barycentric_coordinates<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -1,42 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 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 "barycentric_interpolation.h"
|
||||
#include "parallel_for.h"
|
||||
|
||||
template <
|
||||
typename DerivedD,
|
||||
typename DerivedF,
|
||||
typename DerivedB,
|
||||
typename DerivedI,
|
||||
typename DerivedX>
|
||||
IGL_INLINE void igl::barycentric_interpolation(
|
||||
const Eigen::MatrixBase<DerivedD> & D,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const Eigen::MatrixBase<DerivedB> & B,
|
||||
const Eigen::MatrixBase<DerivedI> & I,
|
||||
Eigen::PlainObjectBase<DerivedX> & X)
|
||||
{
|
||||
assert(B.rows() == I.size());
|
||||
assert(F.cols() == B.cols());
|
||||
X.setZero(B.rows(),D.cols());
|
||||
// should use parallel_for
|
||||
//for(int i = 0;i<X.rows();i++)
|
||||
parallel_for(X.rows(),[&X,&B,&D,&F,&I](const int i)
|
||||
{
|
||||
for(int j = 0;j<F.cols();j++)
|
||||
{
|
||||
X.row(i) += B(i,j) * D.row(F(I(i),j));
|
||||
}
|
||||
},1000);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::barycentric_interpolation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -1,38 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "basename.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
IGL_INLINE std::string igl::basename(const std::string & path)
|
||||
{
|
||||
if(path == "")
|
||||
{
|
||||
return std::string("");
|
||||
}
|
||||
// http://stackoverflow.com/questions/5077693/dirnamephp-similar-function-in-c
|
||||
std::string::const_reverse_iterator last_slash =
|
||||
std::find(
|
||||
path.rbegin(),
|
||||
path.rend(), '/');
|
||||
if( last_slash == path.rend() )
|
||||
{
|
||||
// No slashes found
|
||||
return path;
|
||||
}else if(1 == (last_slash.base() - path.begin()))
|
||||
{
|
||||
// Slash is first char
|
||||
return std::string(path.begin()+1,path.end());
|
||||
}else if(path.end() == last_slash.base() )
|
||||
{
|
||||
// Slash is last char
|
||||
std::string redo = std::string(path.begin(),path.end()-1);
|
||||
return igl::basename(redo);
|
||||
}
|
||||
return std::string(last_slash.base(),path.end());
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
// 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 "bbw.h"
|
||||
#include "min_quad_with_fixed.h"
|
||||
#include "harmonic.h"
|
||||
#include "parallel_for.h"
|
||||
#include <Eigen/Sparse>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <cstdio>
|
||||
|
||||
igl::BBWData::BBWData():
|
||||
partition_unity(false),
|
||||
W0(),
|
||||
active_set_params(),
|
||||
verbosity(0)
|
||||
{
|
||||
// We know that the Bilaplacian is positive semi-definite
|
||||
active_set_params.Auu_pd = true;
|
||||
}
|
||||
|
||||
void igl::BBWData::print()
|
||||
{
|
||||
using namespace std;
|
||||
cout<<"partition_unity: "<<partition_unity<<endl;
|
||||
cout<<"W0=["<<endl<<W0<<endl<<"];"<<endl;
|
||||
}
|
||||
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedEle,
|
||||
typename Derivedb,
|
||||
typename Derivedbc,
|
||||
typename DerivedW>
|
||||
IGL_INLINE bool igl::bbw(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedEle> & Ele,
|
||||
const Eigen::PlainObjectBase<Derivedb> & b,
|
||||
const Eigen::PlainObjectBase<Derivedbc> & bc,
|
||||
igl::BBWData & data,
|
||||
Eigen::PlainObjectBase<DerivedW> & W
|
||||
)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
assert(!data.partition_unity && "partition_unity not implemented yet");
|
||||
// number of domain vertices
|
||||
int n = V.rows();
|
||||
// number of handles
|
||||
int m = bc.cols();
|
||||
// Build biharmonic operator
|
||||
Eigen::SparseMatrix<typename DerivedV::Scalar> Q;
|
||||
harmonic(V,Ele,2,Q);
|
||||
W.derived().resize(n,m);
|
||||
// No linear terms
|
||||
VectorXd c = VectorXd::Zero(n);
|
||||
// No linear constraints
|
||||
SparseMatrix<typename DerivedW::Scalar> A(0,n),Aeq(0,n),Aieq(0,n);
|
||||
VectorXd Beq(0,1),Bieq(0,1);
|
||||
// Upper and lower box constraints (Constant bounds)
|
||||
VectorXd ux = VectorXd::Ones(n);
|
||||
VectorXd lx = VectorXd::Zero(n);
|
||||
active_set_params eff_params = data.active_set_params;
|
||||
if(data.verbosity >= 1)
|
||||
{
|
||||
cout<<"BBW: max_iter: "<<data.active_set_params.max_iter<<endl;
|
||||
cout<<"BBW: eff_max_iter: "<<eff_params.max_iter<<endl;
|
||||
}
|
||||
if(data.verbosity >= 1)
|
||||
{
|
||||
cout<<"BBW: Computing initial weights for "<<m<<" handle"<<
|
||||
(m!=1?"s":"")<<"."<<endl;
|
||||
}
|
||||
min_quad_with_fixed_data<typename DerivedW::Scalar > mqwf;
|
||||
min_quad_with_fixed_precompute(Q,b,Aeq,true,mqwf);
|
||||
min_quad_with_fixed_solve(mqwf,c,bc,Beq,W);
|
||||
// decrement
|
||||
eff_params.max_iter--;
|
||||
bool error = false;
|
||||
// Loop over handles
|
||||
std::mutex critical;
|
||||
const auto & optimize_weight = [&](const int i)
|
||||
{
|
||||
// Quicker exit for paralle_for
|
||||
if(error)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(data.verbosity >= 1)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(critical);
|
||||
cout<<"BBW: Computing weight for handle "<<i+1<<" out of "<<m<<
|
||||
"."<<endl;
|
||||
}
|
||||
VectorXd bci = bc.col(i);
|
||||
VectorXd Wi;
|
||||
// use initial guess
|
||||
Wi = W.col(i);
|
||||
SolverStatus ret = active_set(
|
||||
Q,c,b,bci,Aeq,Beq,Aieq,Bieq,lx,ux,eff_params,Wi);
|
||||
switch(ret)
|
||||
{
|
||||
case SOLVER_STATUS_CONVERGED:
|
||||
break;
|
||||
case SOLVER_STATUS_MAX_ITER:
|
||||
cerr<<"active_set: max iter without convergence."<<endl;
|
||||
break;
|
||||
case SOLVER_STATUS_ERROR:
|
||||
default:
|
||||
cerr<<"active_set error."<<endl;
|
||||
error = true;
|
||||
}
|
||||
W.col(i) = Wi;
|
||||
};
|
||||
|
||||
parallel_for(m,optimize_weight,2);
|
||||
if(error)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
const double min_rowsum = W.rowwise().sum().array().abs().minCoeff();
|
||||
if(min_rowsum < 0.1)
|
||||
{
|
||||
cerr<<"bbw.cpp: Warning, minimum row sum is very low. Consider more "
|
||||
"active set iterations or enforcing partition of unity."<<endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template bool igl::bbw<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<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, igl::BBWData&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 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 "bezier.h"
|
||||
#include <cassert>
|
||||
|
||||
// Adapted from main.c accompanying
|
||||
// An Algorithm for Automatically Fitting Digitized Curves
|
||||
// by Philip J. Schneider
|
||||
// from "Graphics Gems", Academic Press, 1990
|
||||
template <typename DerivedV, typename DerivedP>
|
||||
IGL_INLINE void igl::bezier(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const typename DerivedV::Scalar t,
|
||||
Eigen::PlainObjectBase<DerivedP> & P)
|
||||
{
|
||||
// working local copy
|
||||
DerivedV Vtemp = V;
|
||||
int degree = Vtemp.rows()-1;
|
||||
/* Triangle computation */
|
||||
for (int i = 1; i <= degree; i++)
|
||||
{
|
||||
for (int j = 0; j <= degree-i; j++)
|
||||
{
|
||||
Vtemp.row(j) = ((1.0 - t) * Vtemp.row(j) + t * Vtemp.row(j+1)).eval();
|
||||
}
|
||||
}
|
||||
P = Vtemp.row(0);
|
||||
}
|
||||
|
||||
template <typename DerivedV, typename DerivedT, typename DerivedP>
|
||||
IGL_INLINE void igl::bezier(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedT> & T,
|
||||
Eigen::PlainObjectBase<DerivedP> & P)
|
||||
{
|
||||
P.resize(T.size(),V.cols());
|
||||
for(int i = 0;i<T.size();i++)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedV::Scalar,1,DerivedV::ColsAtCompileTime> Pi;
|
||||
bezier(V,T(i),Pi);
|
||||
P.row(i) = Pi;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VMat, typename DerivedT, typename DerivedP>
|
||||
IGL_INLINE void igl::bezier(
|
||||
const std::vector<VMat> & spline,
|
||||
const Eigen::MatrixBase<DerivedT> & T,
|
||||
Eigen::PlainObjectBase<DerivedP> & P)
|
||||
{
|
||||
if(spline.size() == 0) return;
|
||||
const int m = T.rows();
|
||||
const int dim = spline[0].cols();
|
||||
P.resize(m*spline.size(),dim);
|
||||
for(int c = 0;c<spline.size();c++)
|
||||
{
|
||||
assert(dim == spline[c].cols() && "All curves must have same dimension");
|
||||
DerivedP Pc;
|
||||
bezier(spline[c],T,Pc);
|
||||
P.block(m*c,0,m,dim) = Pc;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::bezier<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::vector<Eigen::Matrix<double, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<double, -1, -1, 0, -1, -1> > > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::bezier<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::bezier<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 1, -1, 1, 1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> >&);
|
||||
#endif
|
||||
@@ -1,93 +0,0 @@
|
||||
#include "bfs.h"
|
||||
#include "list_to_matrix.h"
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
|
||||
template <
|
||||
typename AType,
|
||||
typename DerivedD,
|
||||
typename DerivedP>
|
||||
IGL_INLINE void igl::bfs(
|
||||
const AType & A,
|
||||
const size_t s,
|
||||
Eigen::PlainObjectBase<DerivedD> & D,
|
||||
Eigen::PlainObjectBase<DerivedP> & P)
|
||||
{
|
||||
std::vector<typename DerivedD::Scalar> vD;
|
||||
std::vector<typename DerivedP::Scalar> vP;
|
||||
bfs(A,s,vD,vP);
|
||||
list_to_matrix(vD,D);
|
||||
list_to_matrix(vP,P);
|
||||
}
|
||||
|
||||
template <
|
||||
typename AType,
|
||||
typename DType,
|
||||
typename PType>
|
||||
IGL_INLINE void igl::bfs(
|
||||
const std::vector<std::vector<AType> > & A,
|
||||
const size_t s,
|
||||
std::vector<DType> & D,
|
||||
std::vector<PType> & P)
|
||||
{
|
||||
// number of nodes
|
||||
int N = s+1;
|
||||
for(const auto & Ai : A) for(const auto & a : Ai) N = std::max(N,a+1);
|
||||
std::vector<bool> seen(N,false);
|
||||
P.resize(N,-1);
|
||||
std::queue<std::pair<int,int> > Q;
|
||||
Q.push({s,-1});
|
||||
while(!Q.empty())
|
||||
{
|
||||
const int f = Q.front().first;
|
||||
const int p = Q.front().second;
|
||||
Q.pop();
|
||||
if(seen[f])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
D.push_back(f);
|
||||
P[f] = p;
|
||||
seen[f] = true;
|
||||
for(const auto & n : A[f]) Q.push({n,f});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <
|
||||
typename AType,
|
||||
typename DType,
|
||||
typename PType>
|
||||
IGL_INLINE void igl::bfs(
|
||||
const Eigen::SparseCompressedBase<AType> & A,
|
||||
const size_t s,
|
||||
std::vector<DType> & D,
|
||||
std::vector<PType> & P)
|
||||
{
|
||||
// number of nodes
|
||||
int N = A.rows();
|
||||
assert(A.rows() == A.cols());
|
||||
std::vector<bool> seen(N,false);
|
||||
P.resize(N,-1);
|
||||
std::queue<std::pair<int,int> > Q;
|
||||
Q.push({s,-1});
|
||||
while(!Q.empty())
|
||||
{
|
||||
const int f = Q.front().first;
|
||||
const int p = Q.front().second;
|
||||
Q.pop();
|
||||
if(seen[f])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
D.push_back(f);
|
||||
P[f] = p;
|
||||
seen[f] = true;
|
||||
for(typename AType::InnerIterator it (A,f); it; ++it)
|
||||
{
|
||||
if(it.value()) Q.push({it.index(),f});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "bfs_orient.h"
|
||||
#include "orientable_patches.h"
|
||||
#include "parallel_for.h"
|
||||
#include <Eigen/Sparse>
|
||||
#include <queue>
|
||||
|
||||
template <typename DerivedF, typename DerivedFF, typename DerivedC>
|
||||
IGL_INLINE void igl::bfs_orient(
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedFF> & FF,
|
||||
Eigen::PlainObjectBase<DerivedC> & C)
|
||||
{
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
SparseMatrix<typename DerivedF::Scalar> A;
|
||||
orientable_patches(F,C,A);
|
||||
|
||||
// number of faces
|
||||
const int m = F.rows();
|
||||
// number of patches
|
||||
const int num_cc = C.maxCoeff()+1;
|
||||
VectorXi seen = VectorXi::Zero(m);
|
||||
|
||||
// Edge sets
|
||||
const int ES[3][2] = {{1,2},{2,0},{0,1}};
|
||||
|
||||
if(((void*)&FF) != ((void*)&F))
|
||||
{
|
||||
FF = F;
|
||||
}
|
||||
// loop over patches
|
||||
parallel_for(num_cc,[&](const int c)
|
||||
{
|
||||
queue<typename DerivedF::Scalar> Q;
|
||||
// find first member of patch c
|
||||
for(int f = 0;f<FF.rows();f++)
|
||||
{
|
||||
if(C(f) == c)
|
||||
{
|
||||
Q.push(f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(!Q.empty());
|
||||
while(!Q.empty())
|
||||
{
|
||||
const typename DerivedF::Scalar f = Q.front();
|
||||
Q.pop();
|
||||
if(seen(f) > 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
seen(f)++;
|
||||
// loop over neighbors of f
|
||||
for(typename SparseMatrix<typename DerivedF::Scalar>::InnerIterator it (A,f); it; ++it)
|
||||
{
|
||||
// might be some lingering zeros, and skip self-adjacency
|
||||
if(it.value() != 0 && it.row() != f)
|
||||
{
|
||||
const int n = it.row();
|
||||
assert(n != f);
|
||||
// loop over edges of f
|
||||
for(int efi = 0;efi<3;efi++)
|
||||
{
|
||||
// efi'th edge of face f
|
||||
Vector2i ef(FF(f,ES[efi][0]),FF(f,ES[efi][1]));
|
||||
// loop over edges of n
|
||||
for(int eni = 0;eni<3;eni++)
|
||||
{
|
||||
// eni'th edge of face n
|
||||
Vector2i en(FF(n,ES[eni][0]),FF(n,ES[eni][1]));
|
||||
// Match (half-edges go same direction)
|
||||
if(ef(0) == en(0) && ef(1) == en(1))
|
||||
{
|
||||
// flip face n
|
||||
FF.row(n) = FF.row(n).reverse().eval();
|
||||
}
|
||||
}
|
||||
}
|
||||
// add neighbor to queue
|
||||
Q.push(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
},1000);
|
||||
|
||||
// make sure flip is OK if &FF = &F
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::bfs_orient<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::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
@@ -1,207 +0,0 @@
|
||||
// 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 "biharmonic_coordinates.h"
|
||||
#include "cotmatrix.h"
|
||||
#include "sum.h"
|
||||
#include "massmatrix.h"
|
||||
#include "min_quad_with_fixed.h"
|
||||
#include "crouzeix_raviart_massmatrix.h"
|
||||
#include "crouzeix_raviart_cotmatrix.h"
|
||||
#include "normal_derivative.h"
|
||||
#include "on_boundary.h"
|
||||
#include <Eigen/Sparse>
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedT,
|
||||
typename SType,
|
||||
typename DerivedW>
|
||||
IGL_INLINE bool igl::biharmonic_coordinates(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedT> & T,
|
||||
const std::vector<std::vector<SType> > & S,
|
||||
Eigen::PlainObjectBase<DerivedW> & W)
|
||||
{
|
||||
return biharmonic_coordinates(V,T,S,2,W);
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedT,
|
||||
typename SType,
|
||||
typename DerivedW>
|
||||
IGL_INLINE bool igl::biharmonic_coordinates(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedT> & T,
|
||||
const std::vector<std::vector<SType> > & S,
|
||||
const int k,
|
||||
Eigen::PlainObjectBase<DerivedW> & W)
|
||||
{
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
|
||||
typedef typename DerivedV::Scalar Scalar;
|
||||
typedef typename DerivedT::Scalar Integer;
|
||||
|
||||
// This is not the most efficient way to build A, but follows "Linear
|
||||
// Subspace Design for Real-Time Shape Deformation" [Wang et al. 2015].
|
||||
SparseMatrix<Scalar> A;
|
||||
{
|
||||
DiagonalMatrix<Scalar, Dynamic> Minv;
|
||||
SparseMatrix<Scalar> L, K;
|
||||
Array<bool,Dynamic,Dynamic> C;
|
||||
{
|
||||
Array<bool,Dynamic,1> I;
|
||||
on_boundary(T,I,C);
|
||||
}
|
||||
#ifdef false
|
||||
// Version described in paper is "wrong"
|
||||
// http://www.cs.toronto.edu/~jacobson/images/error-in-linear-subspace-design-for-real-time-shape-deformation-2017-wang-et-al.pdf
|
||||
SparseMatrix<Scalar> N, Z, M;
|
||||
normal_derivative(V,T,N);
|
||||
{
|
||||
std::vector<Triplet<Scalar>> ZIJV;
|
||||
for(int t =0;t<T.rows();t++)
|
||||
{
|
||||
for(int f =0;f<T.cols();f++)
|
||||
{
|
||||
if(C(t,f))
|
||||
{
|
||||
const int i = t+f*T.rows();
|
||||
for(int c = 1;c<T.cols();c++)
|
||||
{
|
||||
ZIJV.emplace_back(T(t,(f+c)%T.cols()),i,1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Z.resize(V.rows(),N.rows());
|
||||
Z.setFromTriplets(ZIJV.begin(),ZIJV.end());
|
||||
N = (Z*N).eval();
|
||||
}
|
||||
cotmatrix(V,T,L);
|
||||
K = N+L;
|
||||
massmatrix(V,T,MASSMATRIX_TYPE_DEFAULT,M);
|
||||
// normalize
|
||||
M /= ((Matrix<Scalar, Dynamic, 1>)M.diagonal()).array().abs().maxCoeff();
|
||||
Minv =
|
||||
((Matrix<Scalar, Dynamic, 1>)M.diagonal().array().inverse()).asDiagonal();
|
||||
#else
|
||||
Eigen::SparseMatrix<Scalar> M;
|
||||
Eigen::Matrix<Integer, Dynamic, Dynamic> E;
|
||||
Eigen::Matrix<Integer, Dynamic, 1> EMAP;
|
||||
crouzeix_raviart_massmatrix(V,T,M,E,EMAP);
|
||||
crouzeix_raviart_cotmatrix(V,T,E,EMAP,L);
|
||||
// Ad #E by #V facet-vertex incidence matrix
|
||||
Eigen::SparseMatrix<Scalar> Ad(E.rows(),V.rows());
|
||||
{
|
||||
std::vector<Eigen::Triplet<Scalar>> AIJV(E.size());
|
||||
for(int e = 0;e<E.rows();e++)
|
||||
{
|
||||
for(int c = 0;c<E.cols();c++)
|
||||
{
|
||||
AIJV[e + c * E.rows()] = Eigen::Triplet<Scalar>(e, E(e, c), 1);
|
||||
}
|
||||
}
|
||||
Ad.setFromTriplets(AIJV.begin(),AIJV.end());
|
||||
}
|
||||
// Degrees
|
||||
Eigen::Matrix<Scalar, Dynamic, 1> De;
|
||||
sum(Ad,2,De);
|
||||
Eigen::DiagonalMatrix<Scalar,Eigen::Dynamic> De_diag =
|
||||
De.array().inverse().matrix().asDiagonal();
|
||||
K = L*(De_diag*Ad);
|
||||
// normalize
|
||||
M /= ((Matrix<Scalar, Dynamic, 1>)M.diagonal()).array().abs().maxCoeff();
|
||||
Minv = ((Matrix<Scalar, Dynamic, 1>)M.diagonal().array().inverse()).asDiagonal();
|
||||
// kill boundary edges
|
||||
for(int f = 0;f<T.rows();f++)
|
||||
{
|
||||
for(int c = 0;c<T.cols();c++)
|
||||
{
|
||||
if(C(f,c))
|
||||
{
|
||||
const int e = EMAP(f+T.rows()*c);
|
||||
Minv.diagonal()(e) = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
switch(k)
|
||||
{
|
||||
default:
|
||||
assert(false && "unsupported");
|
||||
case 2:
|
||||
// For C1 smoothness in 2D, one should use bi-harmonic
|
||||
A = K.transpose() * (Minv * K);
|
||||
break;
|
||||
case 3:
|
||||
// For C1 smoothness in 3D, one should use tri-harmonic
|
||||
A = K.transpose() * (Minv * (-L * (Minv * K)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Vertices in point handles
|
||||
const size_t mp =
|
||||
count_if(S.begin(),S.end(),[](const vector<int> & h){return h.size()==1;});
|
||||
// number of region handles
|
||||
const size_t r = S.size()-mp;
|
||||
// Vertices in region handles
|
||||
size_t mr = 0;
|
||||
for(const auto & h : S)
|
||||
{
|
||||
if(h.size() > 1)
|
||||
{
|
||||
mr += h.size();
|
||||
}
|
||||
}
|
||||
const size_t dim = T.cols()-1;
|
||||
// Might as well be dense... I think...
|
||||
Matrix<Scalar, Dynamic, Dynamic> J = Matrix<Scalar, Dynamic, Dynamic>::Zero(mp+mr,mp+r*(dim+1));
|
||||
Matrix<Integer, Dynamic, 1> b(mp+mr);
|
||||
Matrix<Scalar, Dynamic, Dynamic> H(mp+r*(dim+1),dim);
|
||||
{
|
||||
int v = 0;
|
||||
int c = 0;
|
||||
for(int h = 0;h<S.size();h++)
|
||||
{
|
||||
if(S[h].size()==1)
|
||||
{
|
||||
H.row(c) = V.block(S[h][0],0,1,dim);
|
||||
J(v,c++) = 1;
|
||||
b(v) = S[h][0];
|
||||
v++;
|
||||
}else
|
||||
{
|
||||
assert(S[h].size() >= dim+1);
|
||||
for(int p = 0;p<S[h].size();p++)
|
||||
{
|
||||
for(int d = 0;d<dim;d++)
|
||||
{
|
||||
J(v,c+d) = V(S[h][p],d);
|
||||
}
|
||||
J(v,c+dim) = 1;
|
||||
b(v) = S[h][p];
|
||||
v++;
|
||||
}
|
||||
H.block(c,0,dim+1,dim).setIdentity();
|
||||
c+=dim+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// minimize ½ W' A W'
|
||||
// subject to W(b,:) = J
|
||||
return min_quad_with_fixed(
|
||||
A,Matrix<Scalar, Dynamic, 1>::Zero(A.rows()).eval(),b,J,SparseMatrix<Scalar>(),Matrix<Scalar, Dynamic, 1>(),true,W);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template bool igl::biharmonic_coordinates<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -1,115 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2017 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 "bijective_composite_harmonic_mapping.h"
|
||||
|
||||
#include "slice.h"
|
||||
#include "doublearea.h"
|
||||
#include "harmonic.h"
|
||||
//#include "matlab/MatlabWorkspace.h"
|
||||
#include <iostream>
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename Derivedb,
|
||||
typename Derivedbc,
|
||||
typename DerivedU>
|
||||
IGL_INLINE bool igl::bijective_composite_harmonic_mapping(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const Eigen::MatrixBase<Derivedb> & b,
|
||||
const Eigen::MatrixBase<Derivedbc> & bc,
|
||||
Eigen::PlainObjectBase<DerivedU> & U)
|
||||
{
|
||||
return bijective_composite_harmonic_mapping(V,F,b,bc,1,200,20,true,U);
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename Derivedb,
|
||||
typename Derivedbc,
|
||||
typename DerivedU>
|
||||
IGL_INLINE bool igl::bijective_composite_harmonic_mapping(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const Eigen::MatrixBase<Derivedb> & b,
|
||||
const Eigen::MatrixBase<Derivedbc> & bc,
|
||||
const int min_steps,
|
||||
const int max_steps,
|
||||
const int num_inner_iters,
|
||||
const bool test_for_flips,
|
||||
Eigen::PlainObjectBase<DerivedU> & U)
|
||||
{
|
||||
typedef typename Derivedbc::Scalar Scalar;
|
||||
assert(V.cols() == 2 && bc.cols() == 2 && "Input should be 2D");
|
||||
assert(F.cols() == 3 && "F should contain triangles");
|
||||
int tries = 0;
|
||||
int nsteps = min_steps;
|
||||
Eigen::Matrix<typename Derivedbc::Scalar, Eigen::Dynamic, Eigen::Dynamic> bc0;
|
||||
slice(V,b.col(0),1,bc0);
|
||||
|
||||
// It's difficult to check for flips "robustly" in the sense that the input
|
||||
// mesh might not have positive/consistent sign to begin with.
|
||||
|
||||
while(nsteps<=max_steps)
|
||||
{
|
||||
U = V;
|
||||
int flipped = 0;
|
||||
int nans = 0;
|
||||
int step = 0;
|
||||
for(;step<=nsteps;step++)
|
||||
{
|
||||
const Scalar t = ((Scalar)step)/((Scalar)nsteps);
|
||||
// linearly interpolate boundary conditions
|
||||
// TODO: replace this with something that guarantees a homotopic "morph"
|
||||
// of the boundary conditions. Something like "Homotopic Morphing of
|
||||
// Planar Curves" [Dym et al. 2015] but also handling multiple connected
|
||||
// components.
|
||||
Eigen::Matrix<typename Derivedbc::Scalar, Eigen::Dynamic, Eigen::Dynamic> bct = bc0 + t * (bc - bc0);
|
||||
// Compute dsicrete harmonic map using metric of previous step
|
||||
for(int iter = 0;iter<num_inner_iters;iter++)
|
||||
{
|
||||
//std::cout<<nsteps<<" t: "<<t<<" iter: "<<iter;
|
||||
//igl::matlab::MatlabWorkspace mw;
|
||||
//mw.save(U,"U");
|
||||
//mw.save_index(F,"F");
|
||||
//mw.save_index(b,"b");
|
||||
//mw.save(bct,"bct");
|
||||
//mw.write("numerical.mat");
|
||||
harmonic(Eigen::Matrix<typename DerivedU::Scalar, Eigen::Dynamic, Eigen::Dynamic>(U), F, b, bct, 1, U);
|
||||
igl::slice(U,b.col(0),1,bct);
|
||||
nans = (U.array() != U.array()).count();
|
||||
if(test_for_flips)
|
||||
{
|
||||
Eigen::Matrix<Scalar,Eigen::Dynamic,1> A;
|
||||
doublearea(U,F,A);
|
||||
flipped = (A.array() < 0 ).count();
|
||||
//std::cout<<" "<<flipped<<" nan? "<<(U.array() != U.array()).any()<<std::endl;
|
||||
if(flipped == 0 && nans == 0) break;
|
||||
}
|
||||
}
|
||||
if(flipped > 0 || nans>0) break;
|
||||
}
|
||||
if(flipped == 0 && nans == 0)
|
||||
{
|
||||
return step == nsteps+1;
|
||||
}
|
||||
nsteps *= 2;
|
||||
}
|
||||
//std::cout<<"failed to finish in "<<nsteps<<"..."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template bool igl::bijective_composite_harmonic_mapping<Eigen::Matrix<double, -1, -1, 1, -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>, Eigen::Matrix<double, -1, -1, 1, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template bool igl::bijective_composite_harmonic_mapping<Eigen::Matrix<double, -1, -1, 1, -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>, Eigen::Matrix<double, -1, -1, 1, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, int, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&);
|
||||
#endif
|
||||
@@ -1,71 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 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 "blkdiag.h"
|
||||
|
||||
template <typename Scalar>
|
||||
IGL_INLINE void igl::blkdiag(
|
||||
const std::vector<Eigen::SparseMatrix<Scalar>> & L,
|
||||
Eigen::SparseMatrix<Scalar> & Y)
|
||||
{
|
||||
int nr = 0;
|
||||
int nc = 0;
|
||||
int nnz = 0;
|
||||
for(const auto & A : L)
|
||||
{
|
||||
nr += A.rows();
|
||||
nc += A.cols();
|
||||
}
|
||||
Y.resize(nr,nc);
|
||||
{
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
for(const auto & A : L)
|
||||
{
|
||||
for(int k = 0;k<A.outerSize();++k)
|
||||
{
|
||||
for(typename Eigen::SparseMatrix<Scalar>::InnerIterator it(A,k);it;++it)
|
||||
{
|
||||
Y.insert(i+it.row(),j+k) = it.value();
|
||||
}
|
||||
}
|
||||
i += A.rows();
|
||||
j += A.cols();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename DerivedY>
|
||||
IGL_INLINE void igl::blkdiag(
|
||||
const std::vector<DerivedY> & L,
|
||||
Eigen::PlainObjectBase<DerivedY> & Y)
|
||||
{
|
||||
int nr = 0;
|
||||
int nc = 0;
|
||||
for(const auto & A : L)
|
||||
{
|
||||
nr += A.rows();
|
||||
nc += A.cols();
|
||||
}
|
||||
Y.setZero(nr,nc);
|
||||
{
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
for(const auto & A : L)
|
||||
{
|
||||
Y.block(i,j,A.rows(),A.cols()) = A;
|
||||
i += A.rows();
|
||||
j += A.cols();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// explicit template instantiations
|
||||
template void igl::blkdiag<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::vector<Eigen::Matrix<double, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<double, -1, -1, 0, -1, -1> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::blkdiag<double>(std::vector<Eigen::SparseMatrix<double, 0, int>, std::allocator<Eigen::SparseMatrix<double, 0, int> > > const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
#endif
|
||||
@@ -1,379 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 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 "blue_noise.h"
|
||||
#include "doublearea.h"
|
||||
#include "random_points_on_mesh.h"
|
||||
#include "slice.h"
|
||||
#include "sortrows.h"
|
||||
#include "PI.h"
|
||||
#include "get_seconds.h"
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <random>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
// It is very important that we use 64bit keys to avoid out of bounds (easy to
|
||||
// get to happen with dense samplings (e.g., r = 0.0005*bbd)
|
||||
typedef int64_t BlueNoiseKeyType;
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
namespace igl
|
||||
{
|
||||
// Should probably find and replace with less generic name
|
||||
//
|
||||
// Map 3D subscripts (x,y,z) to unique index (return value)
|
||||
//
|
||||
// Inputs:
|
||||
// w side length of w×w×w integer cube lattice
|
||||
// x subscript along x direction
|
||||
// y subscript along y direction
|
||||
// z subscript along z direction
|
||||
// Returns index value
|
||||
//
|
||||
inline BlueNoiseKeyType blue_noise_key(
|
||||
const BlueNoiseKeyType w, // pass by copy --> int64_t so that multiplication is OK
|
||||
const BlueNoiseKeyType x, // pass by copy --> int64_t so that multiplication is OK
|
||||
const BlueNoiseKeyType y, // pass by copy --> int64_t so that multiplication is OK
|
||||
const BlueNoiseKeyType z) // pass by copy --> int64_t so that multiplication is OK
|
||||
{
|
||||
return x+w*(y+w*z);
|
||||
}
|
||||
// Determine if a query candidate at position X.row(i) is too close to already
|
||||
// selected sites (stored in S).
|
||||
//
|
||||
// Inputs:
|
||||
// X #X by 3 list of raw candidate positions
|
||||
// Xs #Xs by 3 list of corresponding integer cell subscripts
|
||||
// i index of candidate in question
|
||||
// S map from cell index to index into X of selected candidate (or -1 if
|
||||
// cell is currently empty)
|
||||
// rr Poisson disk radius squared
|
||||
// w side length of w×w×w integer cube lattice (into which Xs subscripts)
|
||||
template <
|
||||
typename DerivedX,
|
||||
typename DerivedXs>
|
||||
inline bool blue_noise_far_enough(
|
||||
const Eigen::MatrixBase<DerivedX> & X,
|
||||
const Eigen::MatrixBase<DerivedXs> & Xs,
|
||||
const std::unordered_map<BlueNoiseKeyType,int> & S,
|
||||
const double & rr,
|
||||
const int & w,
|
||||
const int i)
|
||||
{
|
||||
const int xi = Xs(i,0);
|
||||
const int yi = Xs(i,1);
|
||||
const int zi = Xs(i,2);
|
||||
BlueNoiseKeyType k = blue_noise_key(w,xi,yi,zi);
|
||||
int g = 2; // ceil(r/s)
|
||||
for(int x = std::max(xi-g,0);x<=std::min(xi+g,w-1);x++)
|
||||
for(int y = std::max(yi-g,0);y<=std::min(yi+g,w-1);y++)
|
||||
for(int z = std::max(zi-g,0);z<=std::min(zi+g,w-1);z++)
|
||||
{
|
||||
if(x!=xi || y!=yi || z!=zi)
|
||||
{
|
||||
const BlueNoiseKeyType nk = blue_noise_key(w,x,y,z);
|
||||
// have already selected from this cell
|
||||
const auto Siter = S.find(nk);
|
||||
if(Siter !=S.end() && Siter->second >= 0)
|
||||
{
|
||||
const int ni = Siter->second;
|
||||
// too close
|
||||
if( (X.row(i)-X.row(ni)).squaredNorm() < rr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Try to activate a candidate in a given cell
|
||||
//
|
||||
// Inputs:
|
||||
// X #X by 3 list of raw candidate positions
|
||||
// Xs #Xs by 3 list of corresponding integer cell subscripts
|
||||
// rr Poisson disk radius squared
|
||||
// w side length of w×w×w integer cube lattice (into which Xs subscripts)
|
||||
// nk index of cell in which we'd like to activate a candidate
|
||||
// M map from cell index to list of candidates
|
||||
// S map from cell index to index into X of selected candidate (or -1 if
|
||||
// cell is currently empty)
|
||||
// active list of indices into X of active candidates
|
||||
// Outputs:
|
||||
// M visited candidates deemed too close to already selected points are
|
||||
// removed
|
||||
// S updated to reflect activated point (if successful)
|
||||
// active updated to reflect activated point (if successful)
|
||||
// Returns true iff activation was successful
|
||||
template <
|
||||
typename DerivedX,
|
||||
typename DerivedXs>
|
||||
inline bool activate(
|
||||
const Eigen::MatrixBase<DerivedX> & X,
|
||||
const Eigen::MatrixBase<DerivedXs> & Xs,
|
||||
const double & rr,
|
||||
const int & i,
|
||||
const int & w,
|
||||
const BlueNoiseKeyType & nk,
|
||||
std::unordered_map<BlueNoiseKeyType,std::vector<int> > & M,
|
||||
std::unordered_map<BlueNoiseKeyType,int> & S,
|
||||
std::vector<int> & active)
|
||||
{
|
||||
assert(M.count(nk));
|
||||
auto & Mvec = M.find(nk)->second;
|
||||
auto miter = Mvec.begin();
|
||||
while(miter != Mvec.end())
|
||||
{
|
||||
const int mi = *miter;
|
||||
// mi is our candidate sample. Is it far enough from all existing
|
||||
// samples?
|
||||
if(i>=0 && (X.row(i)-X.row(mi)).squaredNorm() > 4.*rr)
|
||||
{
|
||||
// too far skip (reject)
|
||||
miter++;
|
||||
} else if(blue_noise_far_enough(X,Xs,S,rr,w,mi))
|
||||
{
|
||||
active.push_back(mi);
|
||||
S.find(nk)->second = mi;
|
||||
//printf(" found %d\n",mi);
|
||||
return true;
|
||||
}else
|
||||
{
|
||||
// remove forever (instead of incrementing we swap and eat from the
|
||||
// back)
|
||||
//std::swap(*miter,Mvec.back());
|
||||
*miter = Mvec.back();
|
||||
bool was_last = (std::next(miter) == Mvec.end());
|
||||
Mvec.pop_back();
|
||||
if (was_last) {
|
||||
// popping from the vector can invalidate the iterator, if it was
|
||||
// pointing to the last element that was popped. Alternatively,
|
||||
// one could use indices directly...
|
||||
miter = Mvec.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedX,
|
||||
typename DerivedXs,
|
||||
typename URBG>
|
||||
inline bool step(
|
||||
const Eigen::MatrixBase<DerivedX> & X,
|
||||
const Eigen::MatrixBase<DerivedXs> & Xs,
|
||||
const double & rr,
|
||||
const int & w,
|
||||
URBG && urbg,
|
||||
std::unordered_map<BlueNoiseKeyType,std::vector<int> > & M,
|
||||
std::unordered_map<BlueNoiseKeyType,int> & S,
|
||||
std::vector<int> & active,
|
||||
std::vector<int> & collected
|
||||
)
|
||||
{
|
||||
//considered.clear();
|
||||
if(active.size() == 0) return false;
|
||||
// random entry
|
||||
std::uniform_int_distribution<> dis(0, active.size()-1);
|
||||
const int e = dis(urbg);
|
||||
const int i = active[e];
|
||||
//printf("%d\n",i);
|
||||
const int xi = Xs(i,0);
|
||||
const int yi = Xs(i,1);
|
||||
const int zi = Xs(i,2);
|
||||
//printf("%d %d %d - %g %g %g\n",xi,yi,zi,X(i,0),X(i,1),X(i,2));
|
||||
// cell indices of neighbors
|
||||
int g = 4;
|
||||
std::vector<BlueNoiseKeyType> N;N.reserve((1+g*1)^3-1);
|
||||
for(int x = std::max(xi-g,0);x<=std::min(xi+g,w-1);x++)
|
||||
for(int y = std::max(yi-g,0);y<=std::min(yi+g,w-1);y++)
|
||||
for(int z = std::max(zi-g,0);z<=std::min(zi+g,w-1);z++)
|
||||
{
|
||||
if(x!=xi || y!=yi || z!=zi)
|
||||
{
|
||||
//printf(" %d %d %d\n",x,y,z);
|
||||
const BlueNoiseKeyType nk = blue_noise_key(w,x,y,z);
|
||||
// haven't yet selected from this cell?
|
||||
const auto Siter = S.find(nk);
|
||||
if(Siter !=S.end() && Siter->second < 0)
|
||||
{
|
||||
assert(M.find(nk) != M.end());
|
||||
N.emplace_back(nk);
|
||||
}
|
||||
}
|
||||
}
|
||||
//printf(" --------\n");
|
||||
// randomize order: this might be a little paranoid...
|
||||
std::shuffle(std::begin(N), std::end(N), urbg);
|
||||
bool found = false;
|
||||
for(const BlueNoiseKeyType & nk : N)
|
||||
{
|
||||
assert(M.find(nk) != M.end());
|
||||
if(activate(X,Xs,rr,i,w,nk,M,S,active))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found)
|
||||
{
|
||||
// remove i from active list
|
||||
// https://stackoverflow.com/a/60765833/148668
|
||||
collected.push_back(i);
|
||||
//printf(" before: "); for(const int j : active) { printf("%d ",j); } printf("\n");
|
||||
std::swap(active[e], active.back());
|
||||
//printf(" after : "); for(const int j : active) { printf("%d ",j); } printf("\n");
|
||||
active.pop_back();
|
||||
//printf(" removed %d\n",i);
|
||||
}
|
||||
//printf(" active: "); for(const int j : active) { printf("%d ",j); } printf("\n");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedB,
|
||||
typename DerivedFI,
|
||||
typename DerivedP,
|
||||
typename URBG>
|
||||
IGL_INLINE void igl::blue_noise(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const typename DerivedV::Scalar r,
|
||||
Eigen::PlainObjectBase<DerivedB> & B,
|
||||
Eigen::PlainObjectBase<DerivedFI> & FI,
|
||||
Eigen::PlainObjectBase<DerivedP> & P,
|
||||
URBG && urbg)
|
||||
{
|
||||
typedef typename DerivedV::Scalar Scalar;
|
||||
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,1> VectorXS;
|
||||
// float+RowMajor is faster...
|
||||
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,3,Eigen::RowMajor> MatrixX3S;
|
||||
assert(V.cols() == 3 && "Only 3D embeddings allowed");
|
||||
// minimum radius
|
||||
const Scalar min_r = r;
|
||||
// cell size based on 3D distance
|
||||
// It works reasonably well (but is probably biased to use s=2*r/√3 here and
|
||||
// g=1 in the outer loop below.
|
||||
//
|
||||
// One thing to try would be to store a list in S (rather than a single point)
|
||||
// or equivalently a mask over M and just use M as a generic spatial hash
|
||||
// (with arbitrary size) and then tune its size (being careful to make g a
|
||||
// function of r and s; and removing the `if S=-1 checks`)
|
||||
const Scalar s = r/sqrt(3.0);
|
||||
|
||||
const double area =
|
||||
[&](){Eigen::VectorXd A;igl::doublearea(V,F,A);return A.array().sum()/2;}();
|
||||
// Circle packing in the plane has igl::PI*sqrt(3)/6 efficiency
|
||||
const double expected_number_of_points =
|
||||
area * (igl::PI * sqrt(3.0) / 6.0) / (igl::PI * min_r * min_r / 4.0);
|
||||
|
||||
// Make a uniform random sampling with 30*expected_number_of_points.
|
||||
const int nx = 30.0*expected_number_of_points;
|
||||
MatrixX3S X,XB;
|
||||
Eigen::VectorXi XFI;
|
||||
igl::random_points_on_mesh(nx,V,F,XB,XFI,X,urbg);
|
||||
|
||||
// Rescale so that s = 1
|
||||
Eigen::Matrix<int,Eigen::Dynamic,3,Eigen::RowMajor> Xs =
|
||||
((X.rowwise()-X.colwise().minCoeff())/s).template cast<int>();
|
||||
const int w = Xs.maxCoeff()+1;
|
||||
{
|
||||
Eigen::VectorXi I;
|
||||
igl::sortrows(decltype(Xs)(Xs),true,Xs,I);
|
||||
igl::slice(decltype(X)(X),I,1,X);
|
||||
// These two could be spun off in their own thread.
|
||||
igl::slice(decltype(XB)(XB),I,1,XB);
|
||||
igl::slice(decltype(XFI)(XFI),I,1,XFI);
|
||||
}
|
||||
// Initialization
|
||||
std::unordered_map<BlueNoiseKeyType,std::vector<int> > M;
|
||||
std::unordered_map<BlueNoiseKeyType, int > S;
|
||||
// attempted to seed
|
||||
std::unordered_map<BlueNoiseKeyType, int > A;
|
||||
// Q: Too many?
|
||||
// A: Seems to help though.
|
||||
M.reserve(Xs.rows());
|
||||
S.reserve(Xs.rows());
|
||||
for(int i = 0;i<Xs.rows();i++)
|
||||
{
|
||||
BlueNoiseKeyType k = blue_noise_key(w,Xs(i,0),Xs(i,1),Xs(i,2));
|
||||
const auto Miter = M.find(k);
|
||||
if(Miter == M.end())
|
||||
{
|
||||
M.insert({k,{i}});
|
||||
}else
|
||||
{
|
||||
Miter->second.push_back(i);
|
||||
}
|
||||
S.emplace(k,-1);
|
||||
A.emplace(k,false);
|
||||
}
|
||||
|
||||
std::vector<int> active;
|
||||
// precompute r²
|
||||
// Q: is this necessary?
|
||||
const double rr = r*r;
|
||||
std::vector<int> collected;
|
||||
collected.reserve(2.0*expected_number_of_points);
|
||||
|
||||
auto Mouter = M.begin();
|
||||
// Just take the first point as the initial seed
|
||||
const auto initialize = [&]()->bool
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
if(Mouter == M.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const BlueNoiseKeyType k = Mouter->first;
|
||||
// Haven't placed in this cell yet
|
||||
if(S[k]<0)
|
||||
{
|
||||
if(activate(X,Xs,rr,-1,w,k,M,S,active)) return true;
|
||||
}
|
||||
Mouter++;
|
||||
}
|
||||
assert(false && "should not be reachable.");
|
||||
};
|
||||
|
||||
// important if mesh contains many connected components
|
||||
while(initialize())
|
||||
{
|
||||
while(active.size()>0)
|
||||
{
|
||||
step(X,Xs,rr,w,urbg,M,S,active,collected);
|
||||
}
|
||||
}
|
||||
{
|
||||
const int n = collected.size();
|
||||
P.resize(n,3);
|
||||
B.resize(n,3);
|
||||
FI.resize(n);
|
||||
for(int i = 0;i<n;i++)
|
||||
{
|
||||
const int c = collected[i];
|
||||
P.row(i) = X.row(c).template cast<typename DerivedP::Scalar>();
|
||||
B.row(i) = XB.row(c).template cast<typename DerivedB::Scalar>();
|
||||
FI(i) = XFI(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::blue_noise<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, std::mt19937_64 >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, std::mt19937_64&&);
|
||||
template void igl::blue_noise<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, std::mt19937 >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, std::mt19937&&);
|
||||
#endif
|
||||
@@ -1,32 +0,0 @@
|
||||
// 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 "bone_parents.h"
|
||||
|
||||
template <typename DerivedBE, typename DerivedP>
|
||||
IGL_INLINE void igl::bone_parents(
|
||||
const Eigen::MatrixBase<DerivedBE>& BE,
|
||||
Eigen::PlainObjectBase<DerivedP>& P)
|
||||
{
|
||||
P.resize(BE.rows(),1);
|
||||
// Stupid O(n²) version
|
||||
for(int e = 0;e<BE.rows();e++)
|
||||
{
|
||||
P(e) = -1;
|
||||
for(int f = 0;f<BE.rows();f++)
|
||||
{
|
||||
if(BE(e,0) == BE(f,1))
|
||||
{
|
||||
P(e) = f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
template void igl::bone_parents<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
@@ -1,245 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "boundary_conditions.h"
|
||||
|
||||
#include "verbose.h"
|
||||
#include "EPS.h"
|
||||
#include "project_to_line.h"
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
IGL_INLINE bool igl::boundary_conditions(
|
||||
const Eigen::MatrixXd & V ,
|
||||
const Eigen::MatrixXi & /*Ele*/,
|
||||
const Eigen::MatrixXd & C ,
|
||||
const Eigen::VectorXi & P ,
|
||||
const Eigen::MatrixXi & BE ,
|
||||
const Eigen::MatrixXi & CE ,
|
||||
const Eigen::MatrixXi & CF ,
|
||||
Eigen::VectorXi & b ,
|
||||
Eigen::MatrixXd & bc )
|
||||
{
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
|
||||
if(P.size()+BE.rows() == 0)
|
||||
{
|
||||
verbose("^%s: Error: no handles found\n",__FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
vector<int> bci;
|
||||
vector<int> bcj;
|
||||
vector<double> bcv;
|
||||
|
||||
// loop over points
|
||||
for(int p = 0;p<P.size();p++)
|
||||
{
|
||||
VectorXd pos = C.row(P(p));
|
||||
// loop over domain vertices
|
||||
for(int i = 0;i<V.rows();i++)
|
||||
{
|
||||
// Find samples just on pos
|
||||
//Vec3 vi(V(i,0),V(i,1),V(i,2));
|
||||
// EIGEN GOTCHA:
|
||||
// double sqrd = (V.row(i)-pos).array().pow(2).sum();
|
||||
// Must first store in temporary
|
||||
VectorXd vi = V.row(i);
|
||||
double sqrd = (vi-pos).squaredNorm();
|
||||
if(sqrd <= FLOAT_EPS)
|
||||
{
|
||||
//cout<<"sum((["<<
|
||||
// V(i,0)<<" "<<
|
||||
// V(i,1)<<" "<<
|
||||
// V(i,2)<<"] - ["<<
|
||||
// pos(0)<<" "<<
|
||||
// pos(1)<<" "<<
|
||||
// pos(2)<<"]).^2) = "<<sqrd<<endl;
|
||||
bci.push_back(i);
|
||||
bcj.push_back(p);
|
||||
bcv.push_back(1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// loop over bone edges
|
||||
for(int e = 0;e<BE.rows();e++)
|
||||
{
|
||||
// loop over domain vertices
|
||||
for(int i = 0;i<V.rows();i++)
|
||||
{
|
||||
// Find samples from tip up to tail
|
||||
VectorXd tip = C.row(BE(e,0));
|
||||
VectorXd tail = C.row(BE(e,1));
|
||||
// Compute parameter along bone and squared distance
|
||||
double t,sqrd;
|
||||
project_to_line(
|
||||
V(i,0),V(i,1),V(i,2),
|
||||
tip(0),tip(1),tip(2),
|
||||
tail(0),tail(1),tail(2),
|
||||
t,sqrd);
|
||||
if(t>=-FLOAT_EPS && t<=(1.0f+FLOAT_EPS) && sqrd<=FLOAT_EPS)
|
||||
{
|
||||
bci.push_back(i);
|
||||
bcj.push_back(P.size()+e);
|
||||
bcv.push_back(1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// loop over cage edges
|
||||
for(int e = 0;e<CE.rows();e++)
|
||||
{
|
||||
// loop over domain vertices
|
||||
for(int i = 0;i<V.rows();i++)
|
||||
{
|
||||
// Find samples from tip up to tail
|
||||
VectorXd tip = C.row(P(CE(e,0)));
|
||||
VectorXd tail = C.row(P(CE(e,1)));
|
||||
// Compute parameter along bone and squared distance
|
||||
double t,sqrd;
|
||||
project_to_line(
|
||||
V(i,0),V(i,1),V(i,2),
|
||||
tip(0),tip(1),tip(2),
|
||||
tail(0),tail(1),tail(2),
|
||||
t,sqrd);
|
||||
if(t>=-FLOAT_EPS && t<=(1.0f+FLOAT_EPS) && sqrd<=FLOAT_EPS)
|
||||
{
|
||||
bci.push_back(i);
|
||||
bcj.push_back(CE(e,0));
|
||||
bcv.push_back(1.0-t);
|
||||
bci.push_back(i);
|
||||
bcj.push_back(CE(e,1));
|
||||
bcv.push_back(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> vertices_marked(V.rows(), 0);
|
||||
// loop over cage faces
|
||||
for(int f = 0;f<CF.rows();f++)
|
||||
{
|
||||
Vector3d v_0 = C.row(P(CF(f, 0)));
|
||||
Vector3d v_1 = C.row(P(CF(f, 1)));
|
||||
Vector3d v_2 = C.row(P(CF(f, 2)));
|
||||
Vector3d n = (v_1 - v_0).cross(v_2 - v_1);
|
||||
n.normalize();
|
||||
// loop over domain vertices
|
||||
for (int i = 0;i<V.rows();i++)
|
||||
{
|
||||
// ensure each vertex is associated with only one face
|
||||
if (vertices_marked[i])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Vector3d point = V.row(i);
|
||||
Vector3d v = point - v_0;
|
||||
double dist = abs(v.dot(n));
|
||||
Vector3d projected_point = point - dist * n;
|
||||
if (dist <= 1.e-1f)
|
||||
{
|
||||
//barycentric coordinates
|
||||
Vector3d vec_0 = v_1 - v_0, vec_1 = v_2 - v_0, vec_2 = point - v_0;
|
||||
double d00 = vec_0.dot(vec_0);
|
||||
double d01 = vec_0.dot(vec_1);
|
||||
double d11 = vec_1.dot(vec_1);
|
||||
double d20 = vec_2.dot(vec_0);
|
||||
double d21 = vec_2.dot(vec_1);
|
||||
double denom = d00 * d11 - d01 * d01;
|
||||
double v = (d11 * d20 - d01 * d21) / denom;
|
||||
double w = (d00 * d21 - d01 * d20) / denom;
|
||||
double u = 1.0 - v - w;
|
||||
|
||||
if (u>=0. && u<=1.0 && v>=0. && v<=1.0 && w >=0. && w<=1.0)
|
||||
{
|
||||
vertices_marked[i] = 1;
|
||||
bci.push_back(i);
|
||||
bcj.push_back(CF(f, 0));
|
||||
bcv.push_back(u);
|
||||
bci.push_back(i);
|
||||
bcj.push_back(CF(f, 1));
|
||||
bcv.push_back(v);
|
||||
bci.push_back(i);
|
||||
bcj.push_back(CF(f, 2));
|
||||
bcv.push_back(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// find unique boundary indices
|
||||
vector<int> vb = bci;
|
||||
sort(vb.begin(),vb.end());
|
||||
vb.erase(unique(vb.begin(), vb.end()), vb.end());
|
||||
|
||||
b.resize(vb.size());
|
||||
bc = MatrixXd::Zero(vb.size(),P.size()+BE.rows());
|
||||
// Map from boundary index to index in boundary
|
||||
map<int,int> bim;
|
||||
int i = 0;
|
||||
// Also fill in b
|
||||
for(vector<int>::iterator bit = vb.begin();bit != vb.end();bit++)
|
||||
{
|
||||
b(i) = *bit;
|
||||
bim[*bit] = i;
|
||||
i++;
|
||||
}
|
||||
|
||||
// Build BC
|
||||
for(i = 0;i < (int)bci.size();i++)
|
||||
{
|
||||
assert(bim.find(bci[i]) != bim.end());
|
||||
bc(bim[bci[i]],bcj[i]) = bcv[i];
|
||||
}
|
||||
|
||||
// Normalize across rows so that conditions sum to one
|
||||
for(i = 0;i<bc.rows();i++)
|
||||
{
|
||||
double sum = bc.row(i).sum();
|
||||
assert(sum != 0 && "Some boundary vertex getting all zero BCs");
|
||||
bc.row(i).array() /= sum;
|
||||
}
|
||||
|
||||
if(bc.size() == 0)
|
||||
{
|
||||
verbose("^%s: Error: boundary conditions are empty.\n",__FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If there's only a single boundary condition, the following tests
|
||||
// are overzealous.
|
||||
if(bc.cols() == 1)
|
||||
{
|
||||
// If there is only one weight function,
|
||||
// then we expect that there is only one handle.
|
||||
assert(P.rows() + BE.rows() == 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check that every Weight function has at least one boundary value of 1 and
|
||||
// one value of 0
|
||||
for(i = 0;i<bc.cols();i++)
|
||||
{
|
||||
double min_abs_c = bc.col(i).array().abs().minCoeff();
|
||||
double max_c = bc.col(i).maxCoeff();
|
||||
if(min_abs_c > FLOAT_EPS)
|
||||
{
|
||||
verbose("^%s: Error: handle %d does not receive 0 weight\n",__FUNCTION__,i);
|
||||
return false;
|
||||
}
|
||||
if(max_c< (1-FLOAT_EPS))
|
||||
{
|
||||
verbose("^%s: Error: handle %d does not receive 1 weight\n",__FUNCTION__,i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "boundary_facets.h"
|
||||
#include "face_occurrences.h"
|
||||
#include "list_to_matrix.h"
|
||||
#include "matrix_to_list.h"
|
||||
#include "sort.h"
|
||||
#include "unique_rows.h"
|
||||
#include "accumarray.h"
|
||||
#include "slice_mask.h"
|
||||
|
||||
#include <Eigen/Core>
|
||||
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
template <
|
||||
typename DerivedT,
|
||||
typename DerivedF,
|
||||
typename DerivedJ,
|
||||
typename DerivedK>
|
||||
IGL_INLINE void igl::boundary_facets(
|
||||
const Eigen::MatrixBase<DerivedT>& T,
|
||||
Eigen::PlainObjectBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedJ>& J,
|
||||
Eigen::PlainObjectBase<DerivedK>& K)
|
||||
{
|
||||
const int simplex_size = T.cols();
|
||||
// Handle boring base case
|
||||
if(T.rows() == 0)
|
||||
{
|
||||
F.resize(0,simplex_size-1);
|
||||
J.resize(0,1);
|
||||
K.resize(0,1);
|
||||
return;
|
||||
}
|
||||
// Get a list of all facets/edges
|
||||
DerivedF allF(T.rows()*simplex_size,simplex_size-1);
|
||||
switch(simplex_size)
|
||||
{
|
||||
case 4:
|
||||
// Gather faces (e.g., loop over tets)
|
||||
for(int i = 0; i< (int)T.rows();i++)
|
||||
{
|
||||
// get face in correct order
|
||||
allF(i*simplex_size+0,0) = T(i,1);
|
||||
allF(i*simplex_size+0,1) = T(i,3);
|
||||
allF(i*simplex_size+0,2) = T(i,2);
|
||||
// get face in correct order
|
||||
allF(i*simplex_size+1,0) = T(i,0);
|
||||
allF(i*simplex_size+1,1) = T(i,2);
|
||||
allF(i*simplex_size+1,2) = T(i,3);
|
||||
// get face in correct order
|
||||
allF(i*simplex_size+2,0) = T(i,0);
|
||||
allF(i*simplex_size+2,1) = T(i,3);
|
||||
allF(i*simplex_size+2,2) = T(i,1);
|
||||
// get face in correct order
|
||||
allF(i*simplex_size+3,0) = T(i,0);
|
||||
allF(i*simplex_size+3,1) = T(i,1);
|
||||
allF(i*simplex_size+3,2) = T(i,2);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
// Gather edges (loop over triangles)
|
||||
for(int i = 0; i< (int)T.rows();i++)
|
||||
{
|
||||
allF(i*simplex_size+0,0) = T(i,1);
|
||||
allF(i*simplex_size+0,1) = T(i,2);
|
||||
allF(i*simplex_size+1,0) = T(i,2);
|
||||
allF(i*simplex_size+1,1) = T(i,0);
|
||||
allF(i*simplex_size+2,0) = T(i,0);
|
||||
allF(i*simplex_size+2,1) = T(i,1);
|
||||
}
|
||||
}
|
||||
DerivedF sortedF;
|
||||
igl::sort(allF,2,true,sortedF);
|
||||
Eigen::VectorXi m,n;
|
||||
{
|
||||
DerivedF _1;
|
||||
igl::unique_rows(sortedF,_1,m,n);
|
||||
}
|
||||
Eigen::VectorXi C;
|
||||
igl::accumarray(n,1,C);
|
||||
const int ones = (C.array()==1).count();
|
||||
// Resize output to fit number of non-twos
|
||||
F.resize(ones, allF.cols());
|
||||
J.resize(F.rows(),1);
|
||||
K.resize(F.rows(),1);
|
||||
int k = 0;
|
||||
for(int c = 0;c< (int)C.size();c++)
|
||||
{
|
||||
if(C(c) == 1)
|
||||
{
|
||||
const int i = m(c);
|
||||
assert(k<(int)F.rows());
|
||||
F.row(k) = allF.row(i);
|
||||
J(k) = i/simplex_size;
|
||||
K(k) = i%simplex_size;
|
||||
k++;
|
||||
}
|
||||
}
|
||||
assert(k==(int)F.rows());
|
||||
}
|
||||
|
||||
template <typename DerivedT, typename DerivedF>
|
||||
IGL_INLINE void igl::boundary_facets(
|
||||
const Eigen::MatrixBase<DerivedT>& T,
|
||||
Eigen::PlainObjectBase<DerivedF>& F)
|
||||
{
|
||||
Eigen::VectorXi J,K;
|
||||
return boundary_facets(T,F,J,K);
|
||||
}
|
||||
|
||||
template <typename DerivedT, typename Ret>
|
||||
Ret igl::boundary_facets(
|
||||
const Eigen::MatrixBase<DerivedT>& T)
|
||||
{
|
||||
Ret F;
|
||||
igl::boundary_facets(T,F);
|
||||
return F;
|
||||
}
|
||||
|
||||
template <typename IntegerT, typename IntegerF>
|
||||
IGL_INLINE void igl::boundary_facets(
|
||||
const std::vector<std::vector<IntegerT> > & T,
|
||||
std::vector<std::vector<IntegerF> > & F)
|
||||
{
|
||||
// Kept for legacy reasons. Could probably just delete.
|
||||
using namespace std;
|
||||
|
||||
if(T.size() == 0)
|
||||
{
|
||||
F.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
int simplex_size = T[0].size();
|
||||
// Get a list of all faces
|
||||
vector<vector<IntegerF> > allF(
|
||||
T.size()*simplex_size,
|
||||
vector<IntegerF>(simplex_size-1));
|
||||
|
||||
// Gather faces, loop over tets
|
||||
for(int i = 0; i< (int)T.size();i++)
|
||||
{
|
||||
assert((int)T[i].size() == simplex_size);
|
||||
switch(simplex_size)
|
||||
{
|
||||
case 4:
|
||||
// get face in correct order
|
||||
allF[i*simplex_size+0][0] = T[i][1];
|
||||
allF[i*simplex_size+0][1] = T[i][3];
|
||||
allF[i*simplex_size+0][2] = T[i][2];
|
||||
// get face in correct order
|
||||
allF[i*simplex_size+1][0] = T[i][0];
|
||||
allF[i*simplex_size+1][1] = T[i][2];
|
||||
allF[i*simplex_size+1][2] = T[i][3];
|
||||
// get face in correct order
|
||||
allF[i*simplex_size+2][0] = T[i][0];
|
||||
allF[i*simplex_size+2][1] = T[i][3];
|
||||
allF[i*simplex_size+2][2] = T[i][1];
|
||||
// get face in correct order
|
||||
allF[i*simplex_size+3][0] = T[i][0];
|
||||
allF[i*simplex_size+3][1] = T[i][1];
|
||||
allF[i*simplex_size+3][2] = T[i][2];
|
||||
break;
|
||||
case 3:
|
||||
allF[i*simplex_size+0][0] = T[i][1];
|
||||
allF[i*simplex_size+0][1] = T[i][2];
|
||||
allF[i*simplex_size+1][0] = T[i][2];
|
||||
allF[i*simplex_size+1][1] = T[i][0];
|
||||
allF[i*simplex_size+2][0] = T[i][0];
|
||||
allF[i*simplex_size+2][1] = T[i][1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Counts
|
||||
vector<int> C;
|
||||
face_occurrences(allF,C);
|
||||
|
||||
// Q: Why not just count the number of ones?
|
||||
// A: because we are including non-manifold edges as boundary edges
|
||||
int twos = (int) count(C.begin(),C.end(),2);
|
||||
//int ones = (int) count(C.begin(),C.end(),1);
|
||||
// Resize output to fit number of ones
|
||||
F.resize(allF.size() - twos);
|
||||
//F.resize(ones);
|
||||
int k = 0;
|
||||
for(int i = 0;i< (int)allF.size();i++)
|
||||
{
|
||||
if(C[i] != 2)
|
||||
{
|
||||
assert(k<(int)F.size());
|
||||
F[k] = allF[i];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
assert(k==(int)F.size());
|
||||
//if(k != F.size())
|
||||
//{
|
||||
// printf("%d =? %d\n",k,F.size());
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::boundary_facets<int, int>(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
|
||||
//template Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > igl::boundary_facets(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
|
||||
template Eigen::Matrix<int, -1, -1, 0, -1, -1> igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
|
||||
template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
|
||||
#endif
|
||||
@@ -1,154 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Stefan Brugger <stefanbrugger@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 "boundary_loop.h"
|
||||
#include "slice.h"
|
||||
#include "triangle_triangle_adjacency.h"
|
||||
#include "vertex_triangle_adjacency.h"
|
||||
#include "is_border_vertex.h"
|
||||
#include <set>
|
||||
|
||||
template <typename DerivedF, typename Index>
|
||||
IGL_INLINE void igl::boundary_loop(
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
std::vector<std::vector<Index> >& L)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
|
||||
if(F.rows() == 0)
|
||||
return;
|
||||
|
||||
VectorXd Vdummy(F.maxCoeff()+1,1);
|
||||
Eigen::Matrix<typename DerivedF::Scalar, Eigen::Dynamic, Eigen::Dynamic> TT,TTi;
|
||||
vector<std::vector<int> > VF, VFi;
|
||||
triangle_triangle_adjacency(F,TT,TTi);
|
||||
vertex_triangle_adjacency(Vdummy,F,VF,VFi);
|
||||
|
||||
vector<bool> unvisited = is_border_vertex(F);
|
||||
set<int> unseen;
|
||||
for (size_t i = 0; i < unvisited.size(); ++i)
|
||||
{
|
||||
if (unvisited[i])
|
||||
unseen.insert(unseen.end(),i);
|
||||
}
|
||||
|
||||
while (!unseen.empty())
|
||||
{
|
||||
vector<Index> l;
|
||||
|
||||
// Get first vertex of loop
|
||||
int start = *unseen.begin();
|
||||
unseen.erase(unseen.begin());
|
||||
unvisited[start] = false;
|
||||
l.push_back(start);
|
||||
|
||||
bool done = false;
|
||||
while (!done)
|
||||
{
|
||||
// Find next vertex
|
||||
bool newBndEdge = false;
|
||||
int v = l[l.size()-1];
|
||||
int next;
|
||||
for (int i = 0; i < (int)VF[v].size() && !newBndEdge; i++)
|
||||
{
|
||||
int fid = VF[v][i];
|
||||
|
||||
if (TT.row(fid).minCoeff() < 0.) // Face contains boundary edge
|
||||
{
|
||||
int vLoc = -1;
|
||||
if (F(fid,0) == v) vLoc = 0;
|
||||
if (F(fid,1) == v) vLoc = 1;
|
||||
if (F(fid,2) == v) vLoc = 2;
|
||||
|
||||
int vNext = F(fid,(vLoc + 1) % F.cols());
|
||||
|
||||
newBndEdge = false;
|
||||
if (unvisited[vNext] && TT(fid,vLoc) < 0)
|
||||
{
|
||||
next = vNext;
|
||||
newBndEdge = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newBndEdge)
|
||||
{
|
||||
l.push_back(next);
|
||||
unseen.erase(next);
|
||||
unvisited[next] = false;
|
||||
}
|
||||
else
|
||||
done = true;
|
||||
}
|
||||
L.push_back(l);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename DerivedF, typename Index>
|
||||
IGL_INLINE void igl::boundary_loop(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
std::vector<Index>& L)
|
||||
{
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
|
||||
if(F.rows() == 0)
|
||||
return;
|
||||
|
||||
vector<vector<int> > Lall;
|
||||
boundary_loop(F,Lall);
|
||||
|
||||
int idxMax = -1;
|
||||
size_t maxLen = 0;
|
||||
for (size_t i = 0; i < Lall.size(); ++i)
|
||||
{
|
||||
if (Lall[i].size() > maxLen)
|
||||
{
|
||||
maxLen = Lall[i].size();
|
||||
idxMax = i;
|
||||
}
|
||||
}
|
||||
|
||||
//Check for meshes without boundary
|
||||
if (idxMax == -1)
|
||||
{
|
||||
L.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
L.resize(Lall[idxMax].size());
|
||||
for (size_t i = 0; i < Lall[idxMax].size(); ++i)
|
||||
{
|
||||
L[i] = Lall[idxMax][i];
|
||||
}
|
||||
}
|
||||
|
||||
template <typename DerivedF, typename DerivedL>
|
||||
IGL_INLINE void igl::boundary_loop(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedL>& L)
|
||||
{
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
|
||||
if(F.rows() == 0)
|
||||
return;
|
||||
|
||||
vector<int> Lvec;
|
||||
boundary_loop(F,Lvec);
|
||||
|
||||
L.resize(Lvec.size(), 1);
|
||||
for (size_t i = 0; i < Lvec.size(); ++i)
|
||||
L(i) = Lvec[i];
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::boundary_loop<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::boundary_loop<Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
|
||||
#endif
|
||||
@@ -1,105 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 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 "bounding_box.h"
|
||||
#include <iostream>
|
||||
|
||||
template <typename DerivedV, typename DerivedBV, typename DerivedBF>
|
||||
IGL_INLINE void igl::bounding_box(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
Eigen::PlainObjectBase<DerivedBV>& BV,
|
||||
Eigen::PlainObjectBase<DerivedBF>& BF)
|
||||
{
|
||||
return bounding_box(V,0.,BV,BF);
|
||||
}
|
||||
|
||||
template <typename DerivedV, typename DerivedBV, typename DerivedBF>
|
||||
IGL_INLINE void igl::bounding_box(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const typename DerivedV::Scalar pad,
|
||||
Eigen::PlainObjectBase<DerivedBV>& BV,
|
||||
Eigen::PlainObjectBase<DerivedBF>& BF)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
const int dim = V.cols();
|
||||
const auto & minV = V.colwise().minCoeff().array()-pad;
|
||||
const auto & maxV = V.colwise().maxCoeff().array()+pad;
|
||||
// 2^n vertices
|
||||
BV.resize((1ull<<dim),dim);
|
||||
|
||||
// Recursive lambda to generate all 2^n combinations
|
||||
const std::function<void(const int,const int,int*,int)> combos =
|
||||
[&BV,&minV,&maxV,&combos](
|
||||
const int dim,
|
||||
const int i,
|
||||
int * X,
|
||||
const int pre_index)
|
||||
{
|
||||
for(X[i] = 0;X[i]<2;X[i]++)
|
||||
{
|
||||
int index = pre_index*2+X[i];
|
||||
if((i+1)<dim)
|
||||
{
|
||||
combos(dim,i+1,X,index);
|
||||
}else
|
||||
{
|
||||
for(int d = 0;d<dim;d++)
|
||||
{
|
||||
BV(index,d) = (X[d]?minV[d]:maxV[d]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Eigen::VectorXi X(dim);
|
||||
combos(dim,0,X.data(),0);
|
||||
switch(dim)
|
||||
{
|
||||
case 2:
|
||||
BF.resize(4,2);
|
||||
BF<<
|
||||
3,1,
|
||||
1,0,
|
||||
0,2,
|
||||
2,3;
|
||||
break;
|
||||
case 3:
|
||||
BF.resize(12,3);
|
||||
BF<<
|
||||
2,0,6,
|
||||
0,4,6,
|
||||
5,4,0,
|
||||
5,0,1,
|
||||
6,4,5,
|
||||
5,7,6,
|
||||
3,0,2,
|
||||
1,0,3,
|
||||
3,2,6,
|
||||
6,7,3,
|
||||
5,1,3,
|
||||
3,7,5;
|
||||
break;
|
||||
default:
|
||||
assert(false && "Unsupported dimension.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::bounding_box<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::bounding_box<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::bounding_box<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::Matrix<double, -1, -1, 1, -1, -1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::bounding_box<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::bounding_box<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::bounding_box<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -1,26 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "bounding_box_diagonal.h"
|
||||
#include "max.h"
|
||||
#include "min.h"
|
||||
#include <cmath>
|
||||
|
||||
IGL_INLINE double igl::bounding_box_diagonal(
|
||||
const Eigen::MatrixXd & V)
|
||||
{
|
||||
using namespace Eigen;
|
||||
VectorXd maxV,minV;
|
||||
VectorXi maxVI,minVI;
|
||||
igl::max(V,1,maxV,maxVI);
|
||||
igl::min(V,1,minV,minVI);
|
||||
return sqrt((maxV-minV).array().square().sum());
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
#endif
|
||||
@@ -1,21 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "canonical_quaternions.h"
|
||||
|
||||
template <> IGL_INLINE float igl::CANONICAL_VIEW_QUAT<float>(int i, int j)
|
||||
{
|
||||
return (float)igl::CANONICAL_VIEW_QUAT_F[i][j];
|
||||
}
|
||||
template <> IGL_INLINE double igl::CANONICAL_VIEW_QUAT<double>(int i, int j)
|
||||
{
|
||||
return (double)igl::CANONICAL_VIEW_QUAT_D[i][j];
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
#endif
|
||||
@@ -1,263 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "cat.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
// Bug in unsupported/Eigen/SparseExtra needs iostream first
|
||||
#include <iostream>
|
||||
#include <unsupported/Eigen/SparseExtra>
|
||||
|
||||
|
||||
// Sparse matrices need to be handled carefully. Because C++ does not
|
||||
// Template:
|
||||
// Scalar sparse matrix scalar type, e.g. double
|
||||
template <typename Scalar>
|
||||
IGL_INLINE void igl::cat(
|
||||
const int dim,
|
||||
const Eigen::SparseMatrix<Scalar> & A,
|
||||
const Eigen::SparseMatrix<Scalar> & B,
|
||||
Eigen::SparseMatrix<Scalar> & C)
|
||||
{
|
||||
|
||||
assert(dim == 1 || dim == 2);
|
||||
using namespace Eigen;
|
||||
// Special case if B or A is empty
|
||||
if(A.size() == 0)
|
||||
{
|
||||
C = B;
|
||||
return;
|
||||
}
|
||||
if(B.size() == 0)
|
||||
{
|
||||
C = A;
|
||||
return;
|
||||
}
|
||||
|
||||
// This is faster than using DynamicSparseMatrix or setFromTriplets
|
||||
C = SparseMatrix<Scalar>(
|
||||
dim == 1 ? A.rows()+B.rows() : A.rows(),
|
||||
dim == 1 ? A.cols() : A.cols()+B.cols());
|
||||
Eigen::VectorXi per_col = Eigen::VectorXi::Zero(C.cols());
|
||||
if(dim == 1)
|
||||
{
|
||||
assert(A.outerSize() == B.outerSize());
|
||||
for(int k = 0;k<A.outerSize();++k)
|
||||
{
|
||||
for(typename SparseMatrix<Scalar>::InnerIterator it (A,k); it; ++it)
|
||||
{
|
||||
per_col(k)++;
|
||||
}
|
||||
for(typename SparseMatrix<Scalar>::InnerIterator it (B,k); it; ++it)
|
||||
{
|
||||
per_col(k)++;
|
||||
}
|
||||
}
|
||||
}else
|
||||
{
|
||||
for(int k = 0;k<A.outerSize();++k)
|
||||
{
|
||||
for(typename SparseMatrix<Scalar>::InnerIterator it (A,k); it; ++it)
|
||||
{
|
||||
per_col(k)++;
|
||||
}
|
||||
}
|
||||
for(int k = 0;k<B.outerSize();++k)
|
||||
{
|
||||
for(typename SparseMatrix<Scalar>::InnerIterator it (B,k); it; ++it)
|
||||
{
|
||||
per_col(A.cols() + k)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
C.reserve(per_col);
|
||||
if(dim == 1)
|
||||
{
|
||||
for(int k = 0;k<A.outerSize();++k)
|
||||
{
|
||||
for(typename SparseMatrix<Scalar>::InnerIterator it (A,k); it; ++it)
|
||||
{
|
||||
C.insert(it.row(),k) = it.value();
|
||||
}
|
||||
for(typename SparseMatrix<Scalar>::InnerIterator it (B,k); it; ++it)
|
||||
{
|
||||
C.insert(A.rows()+it.row(),k) = it.value();
|
||||
}
|
||||
}
|
||||
}else
|
||||
{
|
||||
for(int k = 0;k<A.outerSize();++k)
|
||||
{
|
||||
for(typename SparseMatrix<Scalar>::InnerIterator it (A,k); it; ++it)
|
||||
{
|
||||
C.insert(it.row(),k) = it.value();
|
||||
}
|
||||
}
|
||||
for(int k = 0;k<B.outerSize();++k)
|
||||
{
|
||||
for(typename SparseMatrix<Scalar>::InnerIterator it (B,k); it; ++it)
|
||||
{
|
||||
C.insert(it.row(),A.cols()+k) = it.value();
|
||||
}
|
||||
}
|
||||
}
|
||||
C.makeCompressed();
|
||||
}
|
||||
|
||||
template <typename Derived, class MatC>
|
||||
IGL_INLINE void igl::cat(
|
||||
const int dim,
|
||||
const Eigen::MatrixBase<Derived> & A,
|
||||
const Eigen::MatrixBase<Derived> & B,
|
||||
MatC & C)
|
||||
{
|
||||
assert(dim == 1 || dim == 2);
|
||||
// Special case if B or A is empty
|
||||
if(A.size() == 0)
|
||||
{
|
||||
C = B;
|
||||
return;
|
||||
}
|
||||
if(B.size() == 0)
|
||||
{
|
||||
C = A;
|
||||
return;
|
||||
}
|
||||
|
||||
if(dim == 1)
|
||||
{
|
||||
assert(A.cols() == B.cols());
|
||||
C.resize(A.rows()+B.rows(),A.cols());
|
||||
C << A,B;
|
||||
}else if(dim == 2)
|
||||
{
|
||||
assert(A.rows() == B.rows());
|
||||
C.resize(A.rows(),A.cols()+B.cols());
|
||||
C << A,B;
|
||||
}else
|
||||
{
|
||||
fprintf(stderr,"cat.h: Error: Unsupported dimension %d\n",dim);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Mat>
|
||||
IGL_INLINE Mat igl::cat(const int dim, const Mat & A, const Mat & B)
|
||||
{
|
||||
assert(dim == 1 || dim == 2);
|
||||
Mat C;
|
||||
igl::cat(dim,A,B,C);
|
||||
return C;
|
||||
}
|
||||
|
||||
template <class Mat>
|
||||
IGL_INLINE void igl::cat(const std::vector<std::vector< Mat > > & A, Mat & C)
|
||||
{
|
||||
using namespace std;
|
||||
// Start with empty matrix
|
||||
C.resize(0,0);
|
||||
for(const auto & row_vec : A)
|
||||
{
|
||||
// Concatenate each row horizontally
|
||||
// Start with empty matrix
|
||||
Mat row(0,0);
|
||||
for(const auto & element : row_vec)
|
||||
{
|
||||
row = cat(2,row,element);
|
||||
}
|
||||
// Concatenate rows vertically
|
||||
C = cat(1,C,row);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename DerivedC>
|
||||
IGL_INLINE void igl::cat(const int dim, const std::vector<T> & A, Eigen::PlainObjectBase<DerivedC> & C)
|
||||
{
|
||||
assert(dim == 1 || dim == 2);
|
||||
using namespace Eigen;
|
||||
|
||||
const int num_mat = A.size();
|
||||
if(num_mat == 0)
|
||||
{
|
||||
C.resize(0,0);
|
||||
return;
|
||||
}
|
||||
|
||||
if(dim == 1)
|
||||
{
|
||||
const int A_cols = A[0].cols();
|
||||
|
||||
int tot_rows = 0;
|
||||
for(const auto & m : A)
|
||||
{
|
||||
tot_rows += m.rows();
|
||||
}
|
||||
|
||||
C.resize(tot_rows, A_cols);
|
||||
|
||||
int cur_row = 0;
|
||||
for(int i = 0; i < num_mat; i++)
|
||||
{
|
||||
assert(A_cols == A[i].cols());
|
||||
C.block(cur_row,0,A[i].rows(),A_cols) = A[i];
|
||||
cur_row += A[i].rows();
|
||||
}
|
||||
}
|
||||
else if(dim == 2)
|
||||
{
|
||||
const int A_rows = A[0].rows();
|
||||
|
||||
int tot_cols = 0;
|
||||
for(const auto & m : A)
|
||||
{
|
||||
tot_cols += m.cols();
|
||||
}
|
||||
|
||||
C.resize(A_rows,tot_cols);
|
||||
|
||||
int cur_col = 0;
|
||||
for(int i = 0; i < num_mat; i++)
|
||||
{
|
||||
assert(A_rows == A[i].rows());
|
||||
C.block(0,cur_col,A_rows,A[i].cols()) = A[i];
|
||||
cur_col += A[i].cols();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"cat.h: Error: Unsupported dimension %d\n",dim);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::cat<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(int, std::vector<Eigen::Matrix<float, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<float, -1, -1, 0, -1, -1> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template Eigen::Matrix<double, -1, -1, 0, -1, -1> igl::cat<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(int, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&);
|
||||
// generated by autoexplicit.sh
|
||||
template Eigen::SparseMatrix<double, 0, int> igl::cat<Eigen::SparseMatrix<double, 0, int> >(int, Eigen::SparseMatrix<double, 0, int> const&, Eigen::SparseMatrix<double, 0, int> const&);
|
||||
// generated by autoexplicit.sh
|
||||
template Eigen::Matrix<int, -1, -1, 0, -1, -1> igl::cat<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&);
|
||||
template void igl::cat<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(int, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::Matrix<double, -1, 1, 0, -1, 1>&);
|
||||
template Eigen::Matrix<int, -1, 1, 0, -1, 1> igl::cat<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(int, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&);
|
||||
template Eigen::Matrix<double, -1, 1, 0, -1, 1> igl::cat<Eigen::Matrix<double, -1, 1, 0, -1, 1> >(int, Eigen::Matrix<double, -1, 1, 0, -1, 1> const&, Eigen::Matrix<double, -1, 1, 0, -1, 1> const&);
|
||||
template void igl::cat<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(int, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
|
||||
template void igl::cat<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1>&);
|
||||
template void igl::cat<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(int, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
|
||||
template void igl::cat<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, std::vector<Eigen::Matrix<int, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<int, -1, -1, 0, -1, -1> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::cat<Eigen::Matrix<int, 1, 4, 1, 1, 4>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, std::vector<Eigen::Matrix<int, 1, 4, 1, 1, 4>, std::allocator<Eigen::Matrix<int, 1, 4, 1, 1, 4> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::cat<Eigen::Matrix<int, 1, 15, 1, 1, 15>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, std::vector<Eigen::Matrix<int, 1, 15, 1, 1, 15>, std::allocator<Eigen::Matrix<int, 1, 15, 1, 1, 15> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::cat<Eigen::Matrix<int, 1, 2, 1, 1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, std::vector<Eigen::Matrix<int, 1, 2, 1, 1, 2>, std::allocator<Eigen::Matrix<int, 1, 2, 1, 1, 2> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::cat<Eigen::Matrix<int, 1, 27, 1, 1, 27>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, std::vector<Eigen::Matrix<int, 1, 27, 1, 1, 27>, std::allocator<Eigen::Matrix<int, 1, 27, 1, 1, 27> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::cat<Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, std::vector<Eigen::Matrix<int, 1, 3, 1, 1, 3>, std::allocator<Eigen::Matrix<int, 1, 3, 1, 1, 3> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::cat<Eigen::Matrix<int, 3, 1, 0, 3, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, std::vector<Eigen::Matrix<int, 3, 1, 0, 3, 1>, std::allocator<Eigen::Matrix<int, 3, 1, 0, 3, 1> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::cat<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(int, std::vector<Eigen::Matrix<double, 1, 3, 1, 1, 3>, std::allocator<Eigen::Matrix<double, 1, 3, 1, 1, 3> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::cat<Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(int, std::vector<Eigen::Matrix<double, 3, 1, 0, 3, 1>, std::allocator<Eigen::Matrix<double, 3, 1, 0, 3, 1> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::cat<Eigen::Matrix<int, 1, -1, 1, 1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, std::vector<Eigen::Matrix<int, 1, -1, 1, 1, -1>, std::allocator<Eigen::Matrix<int, 1, -1, 1, 1, -1> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::cat<Eigen::Matrix<double, 1, 2, 1, 1, 2>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(int, std::vector<Eigen::Matrix<double, 1, 2, 1, 1, 2>, std::allocator<Eigen::Matrix<double, 1, 2, 1, 1, 2> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -1,24 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "ceil.h"
|
||||
#include <cmath>
|
||||
|
||||
template < typename DerivedX, typename DerivedY>
|
||||
IGL_INLINE void igl::ceil(
|
||||
const Eigen::PlainObjectBase<DerivedX>& X,
|
||||
Eigen::PlainObjectBase<DerivedY>& Y)
|
||||
{
|
||||
using namespace std;
|
||||
typedef typename DerivedX::Scalar Scalar;
|
||||
Y = X.unaryExpr([](const Scalar &x)->Scalar{return std::ceil(x);}).template cast<typename DerivedY::Scalar >();
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::ceil<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -1,73 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 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 "centroid.h"
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename Derivedc,
|
||||
typename Derivedvol>
|
||||
IGL_INLINE void igl::centroid(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<Derivedc>& cen,
|
||||
Derivedvol & vol)
|
||||
{
|
||||
using namespace Eigen;
|
||||
assert(F.cols() == 3 && "F should contain triangles.");
|
||||
assert(V.cols() == 3 && "V should contain 3d points.");
|
||||
const int m = F.rows();
|
||||
cen.setZero();
|
||||
vol = 0;
|
||||
// loop over faces
|
||||
for(int f = 0;f<m;f++)
|
||||
{
|
||||
// "Calculating the volume and centroid of a polyhedron in 3d" [Nuernberg 2013]
|
||||
// http://www2.imperial.ac.uk/~rn/centroid.pdf
|
||||
// rename corners
|
||||
typedef Eigen::Matrix<typename DerivedV::Scalar,1,3> RowVector3S;
|
||||
const RowVector3S & a = V.row(F(f,0));
|
||||
const RowVector3S & b = V.row(F(f,1));
|
||||
const RowVector3S & c = V.row(F(f,2));
|
||||
// un-normalized normal
|
||||
const RowVector3S & n = (b-a).cross(c-a);
|
||||
// total volume via divergence theorem: ∫ 1
|
||||
vol += n.dot(a)/6.;
|
||||
// centroid via divergence theorem and midpoint quadrature: ∫ x
|
||||
cen.array() += (1./24.*n.array()*((a+b).array().square() + (b+c).array().square() +
|
||||
(c+a).array().square()).array());
|
||||
}
|
||||
cen *= 1./(2.*vol);
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename Derivedc>
|
||||
IGL_INLINE void igl::centroid(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<Derivedc>& c)
|
||||
{
|
||||
typename Derivedc::Scalar vol;
|
||||
return centroid(V,F,c,vol);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::centroid<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&, double&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::centroid<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, 3, 1, 0, 3, 1>, float>(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> >&, float&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::centroid<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::centroid<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&);
|
||||
template void igl::centroid<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&);
|
||||
template void igl::centroid<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
|
||||
#endif
|
||||
@@ -1,143 +0,0 @@
|
||||
// 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 "circulation.h"
|
||||
#include "list_to_matrix.h"
|
||||
#include <cassert>
|
||||
|
||||
IGL_INLINE std::vector<int> igl::circulation(
|
||||
const int e,
|
||||
const bool ccw,
|
||||
const Eigen::VectorXi & EMAP,
|
||||
const Eigen::MatrixXi & EF,
|
||||
const Eigen::MatrixXi & EI)
|
||||
{
|
||||
// prepare output
|
||||
std::vector<int> N;
|
||||
N.reserve(6);
|
||||
const int m = EMAP.size()/3;
|
||||
assert(m*3 == EMAP.size());
|
||||
const auto & step = [&](
|
||||
const int e,
|
||||
const int ff,
|
||||
int & ne,
|
||||
int & nf)
|
||||
{
|
||||
assert((EF(e,1) == ff || EF(e,0) == ff) && "e should touch ff");
|
||||
//const int fside = EF(e,1)==ff?1:0;
|
||||
const int nside = EF(e,0)==ff?1:0;
|
||||
const int nv = EI(e,nside);
|
||||
// get next face
|
||||
nf = EF(e,nside);
|
||||
// get next edge
|
||||
const int dir = ccw?-1:1;
|
||||
ne = EMAP(nf+m*((nv+dir+3)%3));
|
||||
};
|
||||
// Always start with first face (ccw in step will be sure to turn right
|
||||
// direction)
|
||||
const int f0 = EF(e,0);
|
||||
int fi = f0;
|
||||
int ei = e;
|
||||
while(true)
|
||||
{
|
||||
step(ei,fi,ei,fi);
|
||||
N.push_back(fi);
|
||||
// back to start?
|
||||
if(fi == f0)
|
||||
{
|
||||
assert(ei == e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return N;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::circulation(
|
||||
const int e,
|
||||
const bool ccw,
|
||||
const Eigen::VectorXi & EMAP,
|
||||
const Eigen::MatrixXi & EF,
|
||||
const Eigen::MatrixXi & EI,
|
||||
Eigen::VectorXi & vN)
|
||||
{
|
||||
std::vector<int> N = circulation(e,ccw,EMAP,EF,EI);
|
||||
igl::list_to_matrix(N,vN);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::circulation(
|
||||
const int e,
|
||||
const bool ccw,
|
||||
const Eigen::MatrixXi & F,
|
||||
const Eigen::VectorXi & EMAP,
|
||||
const Eigen::MatrixXi & EF,
|
||||
const Eigen::MatrixXi & EI,
|
||||
/*std::vector<int> & Ne,*/
|
||||
std::vector<int> & Nv,
|
||||
std::vector<int> & Nf)
|
||||
{
|
||||
//
|
||||
// for e --> (bf) and ccw=true
|
||||
//
|
||||
// c---d
|
||||
// / \ / \
|
||||
// a---b-e-f
|
||||
// \ / \ /
|
||||
// g---h
|
||||
//
|
||||
// // (might start with {bhf} depending on edge)
|
||||
// Ne = […] -> [fd db dc cb ca ab ag gb gh hb hf fb]
|
||||
// {upto cylic order}
|
||||
// Nf = […] -> [{bfd}, {bdc}, {bca}, {bag}, {bgh}, {bhf}]
|
||||
// Nv = [d c a g h f]
|
||||
//
|
||||
// prepare output
|
||||
//Ne.clear();Ne.reserve(2*10);
|
||||
Nv.clear();Nv.reserve(10);
|
||||
Nf.clear();Nf.reserve(10);
|
||||
const int m = EMAP.size()/3;
|
||||
assert(m*3 == EMAP.size());
|
||||
const auto & step = [&](
|
||||
const int e,
|
||||
const int ff,
|
||||
int & ne,
|
||||
//int & re,
|
||||
int & rv,
|
||||
int & nf)
|
||||
{
|
||||
assert((EF(e,1) == ff || EF(e,0) == ff) && "e should touch ff");
|
||||
//const int fside = EF(e,1)==ff?1:0;
|
||||
const int nside = EF(e,0)==ff?1:0;
|
||||
const int nv = EI(e,nside);
|
||||
// get next face
|
||||
nf = EF(e,nside);
|
||||
// get next edge
|
||||
const int dir = ccw?-1:1;
|
||||
rv = F(nf,nv);
|
||||
ne = EMAP(nf+m*((nv+dir+3)%3));
|
||||
//re = EMAP(nf+m*((nv+2*dir+3)%3));
|
||||
};
|
||||
// Always start with first face (ccw in step will be sure to turn right
|
||||
// direction)
|
||||
const int f0 = EF(e,0);
|
||||
int fi = f0;
|
||||
int ei = e;
|
||||
while(true)
|
||||
{
|
||||
int re,rv;
|
||||
step(ei,fi,ei/*,re*/,rv,fi);
|
||||
Nf.push_back(fi);
|
||||
//Ne.push_back(re);
|
||||
//Ne.push_back(ei);
|
||||
Nv.push_back(rv);
|
||||
// back to start?
|
||||
if(fi == f0)
|
||||
{
|
||||
assert(ei == e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// 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 "circumradius.h"
|
||||
#include "edge_lengths.h"
|
||||
#include "doublearea.h"
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedR>
|
||||
IGL_INLINE void igl::circumradius(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedR> & R)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,3> l;
|
||||
igl::edge_lengths(V,F,l);
|
||||
DerivedR A;
|
||||
igl::doublearea(l,0.,A);
|
||||
// use formula: R=abc/(4*area) to compute the circum radius
|
||||
R = l.col(0).array() * l.col(1).array() * l.col(2).array() / (2.0*A.array());
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
template void igl::circumradius<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -1,373 +0,0 @@
|
||||
// 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 "decimate_trivial_callbacks.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 & 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_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(Nsv,Ndv))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// OVERLOAD: caller may have just computed this
|
||||
//
|
||||
// Important to grab neighbors of d before monkeying with edges
|
||||
const std::vector<int> & nV2Fd = (!eflip ? Nsf : Ndf);
|
||||
|
||||
// The following implementation strongly relies on s<d
|
||||
assert(s<d && "s should be less than d");
|
||||
// move source and destination to placement
|
||||
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. Nah, this is handled by (F(f,v) == d)
|
||||
//
|
||||
// Don't attempt to use Nde,Nse here because EMAP has changed
|
||||
{
|
||||
int p1 = -1;
|
||||
for(auto f : nV2Fd)
|
||||
{
|
||||
for(int v = 0;v<3;v++)
|
||||
{
|
||||
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
|
||||
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 decimate_cost_and_placement_callback & cost_and_placement,
|
||||
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,e1,e2,f1,f2;
|
||||
decimate_pre_collapse_callback always_try;
|
||||
decimate_post_collapse_callback never_care;
|
||||
decimate_trivial_callbacks(always_try,never_care);
|
||||
return
|
||||
collapse_edge(
|
||||
cost_and_placement,always_try,never_care,
|
||||
V,F,E,EMAP,EF,EI,Q,EQ,C,e,e1,e2,f1,f2);
|
||||
}
|
||||
|
||||
IGL_INLINE bool igl::collapse_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,e1,e2,f1,f2;
|
||||
return
|
||||
collapse_edge(
|
||||
cost_and_placement,pre_collapse,post_collapse,
|
||||
V,F,E,EMAP,EF,EI,Q,EQ,C,e,e1,e2,f1,f2);
|
||||
}
|
||||
|
||||
|
||||
IGL_INLINE bool igl::collapse_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 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;
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
// 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_small_triangles.h"
|
||||
|
||||
#include "bounding_box_diagonal.h"
|
||||
#include "doublearea.h"
|
||||
#include "edge_lengths.h"
|
||||
#include "colon.h"
|
||||
#include "faces_first.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void igl::collapse_small_triangles(
|
||||
const Eigen::MatrixXd & V,
|
||||
const Eigen::MatrixXi & F,
|
||||
const double eps,
|
||||
Eigen::MatrixXi & FF)
|
||||
{
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
|
||||
// Compute bounding box diagonal length
|
||||
double bbd = bounding_box_diagonal(V);
|
||||
MatrixXd l;
|
||||
edge_lengths(V,F,l);
|
||||
VectorXd dblA;
|
||||
doublearea(l,0.,dblA);
|
||||
|
||||
// Minimum area tolerance
|
||||
const double min_dblarea = 2.0*eps*bbd*bbd;
|
||||
|
||||
Eigen::VectorXi FIM = colon<int>(0,V.rows()-1);
|
||||
int num_edge_collapses = 0;
|
||||
// Loop over triangles
|
||||
for(int f = 0;f<F.rows();f++)
|
||||
{
|
||||
if(dblA(f) < min_dblarea)
|
||||
{
|
||||
double minl = 0;
|
||||
int minli = -1;
|
||||
// Find shortest edge
|
||||
for(int e = 0;e<3;e++)
|
||||
{
|
||||
if(minli==-1 || l(f,e)<minl)
|
||||
{
|
||||
minli = e;
|
||||
minl = l(f,e);
|
||||
}
|
||||
}
|
||||
double maxl = 0;
|
||||
int maxli = -1;
|
||||
// Find longest edge
|
||||
for(int e = 0;e<3;e++)
|
||||
{
|
||||
if(maxli==-1 || l(f,e)>maxl)
|
||||
{
|
||||
maxli = e;
|
||||
maxl = l(f,e);
|
||||
}
|
||||
}
|
||||
// Be sure that min and max aren't the same
|
||||
maxli = (minli==maxli?(minli+1)%3:maxli);
|
||||
|
||||
// Collapse min edge maintaining max edge: i-->j
|
||||
// Q: Why this direction?
|
||||
int i = maxli;
|
||||
int j = ((minli+1)%3 == maxli ? (minli+2)%3: (minli+1)%3);
|
||||
assert(i != minli);
|
||||
assert(j != minli);
|
||||
assert(i != j);
|
||||
FIM(F(f,i)) = FIM(F(f,j));
|
||||
num_edge_collapses++;
|
||||
}
|
||||
}
|
||||
|
||||
// Reindex faces
|
||||
MatrixXi rF = F;
|
||||
// Loop over triangles
|
||||
for(int f = 0;f<rF.rows();f++)
|
||||
{
|
||||
for(int i = 0;i<rF.cols();i++)
|
||||
{
|
||||
rF(f,i) = FIM(rF(f,i));
|
||||
}
|
||||
}
|
||||
|
||||
FF.resizeLike(rF);
|
||||
int num_face_collapses=0;
|
||||
// Only keep uncollapsed faces
|
||||
{
|
||||
int ff = 0;
|
||||
// Loop over triangles
|
||||
for(int f = 0;f<rF.rows();f++)
|
||||
{
|
||||
bool collapsed = false;
|
||||
// Check if any indices are the same
|
||||
for(int i = 0;i<rF.cols();i++)
|
||||
{
|
||||
for(int j = i+1;j<rF.cols();j++)
|
||||
{
|
||||
if(rF(f,i)==rF(f,j))
|
||||
{
|
||||
collapsed = true;
|
||||
num_face_collapses++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!collapsed)
|
||||
{
|
||||
FF.row(ff++) = rF.row(f);
|
||||
}
|
||||
}
|
||||
// Use conservative resize
|
||||
FF.conservativeResize(ff,FF.cols());
|
||||
}
|
||||
//cout<<"num_edge_collapses: "<<num_edge_collapses<<endl;
|
||||
//cout<<"num_face_collapses: "<<num_face_collapses<<endl;
|
||||
if(num_edge_collapses == 0)
|
||||
{
|
||||
// There must have been a "collapsed edge" in the input
|
||||
assert(num_face_collapses==0);
|
||||
// Base case
|
||||
return;
|
||||
}
|
||||
|
||||
//// force base case
|
||||
//return;
|
||||
|
||||
MatrixXi recFF = FF;
|
||||
return collapse_small_triangles(V,recFF,eps,FF);
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "colon.h"
|
||||
#include "LinSpaced.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
template <typename L,typename S,typename H,typename T>
|
||||
IGL_INLINE void igl::colon(
|
||||
const L low,
|
||||
const S step,
|
||||
const H hi,
|
||||
Eigen::Matrix<T,Eigen::Dynamic,1> & I)
|
||||
{
|
||||
const H size = ((hi-low)/step)+1;
|
||||
I = igl::LinSpaced<Eigen::Matrix<T,Eigen::Dynamic,1> >(size,low,low+step*(size-1));
|
||||
}
|
||||
|
||||
template <typename L,typename H,typename T>
|
||||
IGL_INLINE void igl::colon(
|
||||
const L low,
|
||||
const H hi,
|
||||
Eigen::Matrix<T,Eigen::Dynamic,1> & I)
|
||||
{
|
||||
return igl::colon(low,(T)1,hi,I);
|
||||
}
|
||||
|
||||
template <typename T,typename L,typename H>
|
||||
IGL_INLINE Eigen::Matrix<T,Eigen::Dynamic,1> igl::colon(
|
||||
const L low,
|
||||
const H hi)
|
||||
{
|
||||
Eigen::Matrix<T,Eigen::Dynamic,1> I;
|
||||
igl::colon(low,hi,I);
|
||||
return I;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template Eigen::Matrix<int, -1, 1, 0, -1, 1> igl::colon<int, int, int>(int, int);
|
||||
template Eigen::Matrix<int, -1, 1, 0, -1, 1> igl::colon<int, int, long>(int, long);
|
||||
template Eigen::Matrix<int, -1, 1, 0, -1, 1> igl::colon<int, int, long long int>(int, long long int);
|
||||
template Eigen::Matrix<double, -1, 1, 0, -1, 1> igl::colon<double, double, double>(double, double);
|
||||
template void igl::colon<int, long, double>(int, long, Eigen::Matrix<double, -1, 1, 0, -1, 1> &);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::colon<int, long, int, int>(int, long, int, Eigen::Matrix<int, -1, 1, 0, -1, 1> &);
|
||||
template void igl::colon<int, int, long, int>(int, int, long, Eigen::Matrix<int, -1, 1, 0, -1, 1> &);
|
||||
template void igl::colon<int, long, int>(int, long, Eigen::Matrix<int, -1, 1, 0, -1, 1> &);
|
||||
template void igl::colon<int, int, int>(int, int, Eigen::Matrix<int, -1, 1, 0, -1, 1> &);
|
||||
template void igl::colon<int, long long int, int>(int, long long int, Eigen::Matrix<int, -1, 1, 0, -1, 1> &);
|
||||
template void igl::colon<int, int, int, int>(int, int, int, Eigen::Matrix<int, -1, 1, 0, -1, 1> &);
|
||||
template void igl::colon<int, long, long>(int, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> &);
|
||||
template void igl::colon<int, double, double, double>(int, double, double, Eigen::Matrix<double, -1, 1, 0, -1, 1> &);
|
||||
template void igl::colon<double, double, double>(double, double, Eigen::Matrix<double, -1, 1, 0, -1, 1> &);
|
||||
template void igl::colon<double, double, double, double>(double, double, double, Eigen::Matrix<double, -1, 1, 0, -1, 1> &);
|
||||
template void igl::colon<int, int, long>(int, int, Eigen::Matrix<long, -1, 1, 0, -1, 1> &);
|
||||
template void igl::colon<int, int, double>(int, int, Eigen::Matrix<double, -1, 1, 0, -1, 1> &);
|
||||
#ifdef WIN32
|
||||
template void igl::colon<int, __int64, double>(int, __int64, class Eigen::Matrix<double, -1, 1, 0, -1, 1> &);
|
||||
template void igl::colon<int, long long, long>(int, long long, class Eigen::Matrix<long, -1, 1, 0, -1, 1> &);
|
||||
template void igl::colon<int, __int64, __int64>(int, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1> &);
|
||||
#endif
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,27 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "column_to_quats.h"
|
||||
IGL_INLINE bool igl::column_to_quats(
|
||||
const Eigen::VectorXd & Q,
|
||||
std::vector<
|
||||
Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & vQ)
|
||||
{
|
||||
using namespace Eigen;
|
||||
if(Q.size() % 4 != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const int nQ = Q.size()/4;
|
||||
vQ.resize(nQ);
|
||||
for(int q=0;q<nQ;q++)
|
||||
{
|
||||
// Constructor uses wxyz
|
||||
vQ[q] = Quaterniond( Q(q*4+3), Q(q*4+0), Q(q*4+1), Q(q*4+2));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 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 "columnize.h"
|
||||
#include <cassert>
|
||||
|
||||
template <typename DerivedA, typename DerivedB>
|
||||
IGL_INLINE void igl::columnize(
|
||||
const Eigen::PlainObjectBase<DerivedA> & A,
|
||||
const int k,
|
||||
const int dim,
|
||||
Eigen::PlainObjectBase<DerivedB> & B)
|
||||
{
|
||||
// Eigen matrices must be 2d so dim must be only 1 or 2
|
||||
assert(dim == 1 || dim == 2);
|
||||
|
||||
// block height, width, and number of blocks
|
||||
int m,n;
|
||||
if(dim == 1)
|
||||
{
|
||||
m = A.rows()/k;
|
||||
assert(m*(int)k == (int)A.rows());
|
||||
n = A.cols();
|
||||
}else// dim == 2
|
||||
{
|
||||
m = A.rows();
|
||||
n = A.cols()/k;
|
||||
assert(n*(int)k == (int)A.cols());
|
||||
}
|
||||
|
||||
// resize output
|
||||
B.resize(A.rows()*A.cols(),1);
|
||||
|
||||
for(int b = 0;b<(int)k;b++)
|
||||
{
|
||||
for(int i = 0;i<m;i++)
|
||||
{
|
||||
for(int j = 0;j<n;j++)
|
||||
{
|
||||
if(dim == 1)
|
||||
{
|
||||
B(j*m*k+i*k+b) = A(i+b*m,j);
|
||||
}else
|
||||
{
|
||||
B(j*m*k+i*k+b) = A(i,b*n+j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::columnize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::columnize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::columnize<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::columnize<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
@@ -1,155 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@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 "comb_cross_field.h"
|
||||
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <Eigen/Geometry>
|
||||
#include "per_face_normals.h"
|
||||
#include "is_border_vertex.h"
|
||||
#include "rotation_matrix_from_directions.h"
|
||||
|
||||
#include "triangle_triangle_adjacency.h"
|
||||
|
||||
namespace igl {
|
||||
template <typename DerivedV, typename DerivedF>
|
||||
class Comb
|
||||
{
|
||||
public:
|
||||
|
||||
const Eigen::MatrixBase<DerivedV> &V;
|
||||
const Eigen::MatrixBase<DerivedF> &F;
|
||||
const Eigen::MatrixBase<DerivedV> &PD1;
|
||||
const Eigen::MatrixBase<DerivedV> &PD2;
|
||||
DerivedV N;
|
||||
|
||||
private:
|
||||
// internal
|
||||
DerivedF TT;
|
||||
DerivedF TTi;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
static inline double Sign(double a){return (double)((a>0)?+1:-1);}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// returns the 90 deg rotation of a (around n) most similar to target b
|
||||
/// a and b should be in the same plane orthogonal to N
|
||||
static inline Eigen::Matrix<typename DerivedV::Scalar, 3, 1> K_PI_new(const Eigen::Matrix<typename DerivedV::Scalar, 3, 1>& a,
|
||||
const Eigen::Matrix<typename DerivedV::Scalar, 3, 1>& b,
|
||||
const Eigen::Matrix<typename DerivedV::Scalar, 3, 1>& n)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedV::Scalar, 3, 1> c = (a.cross(n)).normalized();
|
||||
typename DerivedV::Scalar scorea = a.dot(b);
|
||||
typename DerivedV::Scalar scorec = c.dot(b);
|
||||
if (fabs(scorea)>=fabs(scorec))
|
||||
return a*Sign(scorea);
|
||||
else
|
||||
return c*Sign(scorec);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public:
|
||||
inline Comb(const Eigen::MatrixBase<DerivedV> &_V,
|
||||
const Eigen::MatrixBase<DerivedF> &_F,
|
||||
const Eigen::MatrixBase<DerivedV> &_PD1,
|
||||
const Eigen::MatrixBase<DerivedV> &_PD2
|
||||
):
|
||||
V(_V),
|
||||
F(_F),
|
||||
PD1(_PD1),
|
||||
PD2(_PD2)
|
||||
{
|
||||
igl::per_face_normals(V,F,N);
|
||||
igl::triangle_triangle_adjacency(F,TT,TTi);
|
||||
}
|
||||
inline void comb(Eigen::PlainObjectBase<DerivedV> &PD1out,
|
||||
Eigen::PlainObjectBase<DerivedV> &PD2out)
|
||||
{
|
||||
// PD1out = PD1;
|
||||
// PD2out = PD2;
|
||||
PD1out.setZero(F.rows(),3);PD1out<<PD1;
|
||||
PD2out.setZero(F.rows(),3);PD2out<<PD2;
|
||||
|
||||
Eigen::VectorXi mark = Eigen::VectorXi::Constant(F.rows(),false);
|
||||
|
||||
std::deque<int> d;
|
||||
|
||||
while (!mark.all()) // Stop until all vertices are marked
|
||||
{
|
||||
int unmarked = 0;
|
||||
while (mark(unmarked))
|
||||
unmarked++;
|
||||
|
||||
d.push_back(unmarked);
|
||||
mark(unmarked) = true;
|
||||
|
||||
while (!d.empty())
|
||||
{
|
||||
int f0 = d.at(0);
|
||||
d.pop_front();
|
||||
for (int k=0; k<3; k++)
|
||||
{
|
||||
int f1 = TT(f0,k);
|
||||
if (f1==-1) continue;
|
||||
if (mark(f1)) continue;
|
||||
|
||||
Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir0 = PD1out.row(f0);
|
||||
Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir1 = PD1out.row(f1);
|
||||
Eigen::Matrix<typename DerivedV::Scalar, 3, 1> n0 = N.row(f0);
|
||||
Eigen::Matrix<typename DerivedV::Scalar, 3, 1> n1 = N.row(f1);
|
||||
|
||||
|
||||
Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir0Rot = igl::rotation_matrix_from_directions(n0, n1)*dir0;
|
||||
dir0Rot.normalize();
|
||||
Eigen::Matrix<typename DerivedV::Scalar, 3, 1> targD = K_PI_new(dir1,dir0Rot,n1);
|
||||
|
||||
PD1out.row(f1) = targD;
|
||||
PD2out.row(f1) = n1.cross(targD).normalized();
|
||||
|
||||
mark(f1) = true;
|
||||
d.push_back(f1);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// everything should be marked
|
||||
for (int i=0; i<F.rows(); i++)
|
||||
{
|
||||
assert(mark(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
template <typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE void igl::comb_cross_field(const Eigen::MatrixBase<DerivedV> &V,
|
||||
const Eigen::MatrixBase<DerivedF> &F,
|
||||
const Eigen::MatrixBase<DerivedV> &PD1,
|
||||
const Eigen::MatrixBase<DerivedV> &PD2,
|
||||
Eigen::PlainObjectBase<DerivedV> &PD1out,
|
||||
Eigen::PlainObjectBase<DerivedV> &PD2out)
|
||||
{
|
||||
igl::Comb<DerivedV, DerivedF> cmb(V, F, PD1, PD2);
|
||||
cmb.comb(PD1out, PD2out);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::comb_cross_field<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::comb_cross_field<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -1,78 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@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/.
|
||||
|
||||
#ifdef WIN32
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
#include <cmath>
|
||||
|
||||
#include "comb_frame_field.h"
|
||||
#include "local_basis.h"
|
||||
#include "PI.h"
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedP>
|
||||
IGL_INLINE void igl::comb_frame_field(const Eigen::MatrixBase<DerivedV> &V,
|
||||
const Eigen::MatrixBase<DerivedF> &F,
|
||||
const Eigen::MatrixBase<DerivedP> &PD1,
|
||||
const Eigen::MatrixBase<DerivedP> &PD2,
|
||||
const Eigen::MatrixBase<DerivedP> &BIS1_combed,
|
||||
const Eigen::MatrixBase<DerivedP> &BIS2_combed,
|
||||
Eigen::PlainObjectBase<DerivedP> &PD1_combed,
|
||||
Eigen::PlainObjectBase<DerivedP> &PD2_combed)
|
||||
{
|
||||
DerivedV B1, B2, B3;
|
||||
igl::local_basis(V,F,B1,B2,B3);
|
||||
|
||||
PD1_combed.resize(BIS1_combed.rows(),3);
|
||||
PD2_combed.resize(BIS2_combed.rows(),3);
|
||||
|
||||
for (unsigned i=0; i<PD1.rows();++i)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedP::Scalar,4,3> DIRs;
|
||||
DIRs <<
|
||||
PD1.row(i),
|
||||
-PD1.row(i),
|
||||
PD2.row(i),
|
||||
-PD2.row(i);
|
||||
|
||||
std::vector<double> a(4);
|
||||
|
||||
|
||||
double a_combed = atan2(B2.row(i).dot(BIS1_combed.row(i)),B1.row(i).dot(BIS1_combed.row(i)));
|
||||
|
||||
// center on the combed sector center
|
||||
for (unsigned j=0;j<4;++j)
|
||||
{
|
||||
a[j] = atan2(B2.row(i).dot(DIRs.row(j)),B1.row(i).dot(DIRs.row(j))) - a_combed;
|
||||
//make it positive by adding some multiple of 2pi
|
||||
a[j] += std::ceil (std::max(0., -a[j]) / (igl::PI*2.)) * (igl::PI*2.);
|
||||
//take modulo 2pi
|
||||
a[j] = fmod(a[j], (igl::PI*2.));
|
||||
}
|
||||
// now the max is u and the min is v
|
||||
|
||||
int m = std::min_element(a.begin(),a.end())-a.begin();
|
||||
int M = std::max_element(a.begin(),a.end())-a.begin();
|
||||
|
||||
assert(
|
||||
((m>=0 && m<=1) && (M>=2 && M<=3))
|
||||
||
|
||||
((m>=2 && m<=3) && (M>=0 && M<=1))
|
||||
);
|
||||
|
||||
PD1_combed.row(i) = DIRs.row(m);
|
||||
PD2_combed.row(i) = DIRs.row(M);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::comb_frame_field<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::comb_frame_field<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -1,132 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Nico Pietroni <nico.pietroni@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 "comb_line_field.h"
|
||||
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include "per_face_normals.h"
|
||||
#include "is_border_vertex.h"
|
||||
#include "rotation_matrix_from_directions.h"
|
||||
|
||||
#include "triangle_triangle_adjacency.h"
|
||||
|
||||
namespace igl {
|
||||
template <typename DerivedV, typename DerivedF>
|
||||
class CombLine
|
||||
{
|
||||
public:
|
||||
|
||||
const Eigen::MatrixBase<DerivedV> &V;
|
||||
const Eigen::MatrixBase<DerivedF> &F;
|
||||
const Eigen::MatrixBase<DerivedV> &PD1;
|
||||
DerivedV N;
|
||||
|
||||
private:
|
||||
// internal
|
||||
DerivedF TT;
|
||||
DerivedF TTi;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
static inline double Sign(double a){return (double)((a>0)?+1:-1);}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// returns the 180 deg rotation of a (around n) most similar to target b
|
||||
// a and b should be in the same plane orthogonal to N
|
||||
static inline Eigen::Matrix<typename DerivedV::Scalar, 3, 1> K_PI_line(const Eigen::Matrix<typename DerivedV::Scalar, 3, 1>& a,
|
||||
const Eigen::Matrix<typename DerivedV::Scalar, 3, 1>& b)
|
||||
{
|
||||
typename DerivedV::Scalar scorea = a.dot(b);
|
||||
if (scorea<0)
|
||||
return -a;
|
||||
else
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public:
|
||||
|
||||
inline CombLine(const Eigen::MatrixBase<DerivedV> &_V,
|
||||
const Eigen::MatrixBase<DerivedF> &_F,
|
||||
const Eigen::MatrixBase<DerivedV> &_PD1):
|
||||
V(_V),
|
||||
F(_F),
|
||||
PD1(_PD1)
|
||||
{
|
||||
igl::per_face_normals(V,F,N);
|
||||
igl::triangle_triangle_adjacency(F,TT,TTi);
|
||||
}
|
||||
|
||||
inline void comb(Eigen::PlainObjectBase<DerivedV> &PD1out)
|
||||
{
|
||||
PD1out.setZero(F.rows(),3);PD1out<<PD1;
|
||||
|
||||
Eigen::VectorXi mark = Eigen::VectorXi::Constant(F.rows(),false);
|
||||
|
||||
std::deque<int> d;
|
||||
|
||||
d.push_back(0);
|
||||
mark(0) = true;
|
||||
|
||||
while (!d.empty())
|
||||
{
|
||||
int f0 = d.at(0);
|
||||
d.pop_front();
|
||||
for (int k=0; k<3; k++)
|
||||
{
|
||||
int f1 = TT(f0,k);
|
||||
if (f1==-1) continue;
|
||||
if (mark(f1)) continue;
|
||||
|
||||
Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir0 = PD1out.row(f0);
|
||||
Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir1 = PD1out.row(f1);
|
||||
Eigen::Matrix<typename DerivedV::Scalar, 3, 1> n0 = N.row(f0);
|
||||
Eigen::Matrix<typename DerivedV::Scalar, 3, 1> n1 = N.row(f1);
|
||||
|
||||
Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir0Rot = igl::rotation_matrix_from_directions(n0, n1)*dir0;
|
||||
dir0Rot.normalize();
|
||||
Eigen::Matrix<typename DerivedV::Scalar, 3, 1> targD = K_PI_line(dir1,dir0Rot);
|
||||
|
||||
PD1out.row(f1) = targD;
|
||||
//PD2out.row(f1) = n1.cross(targD).normalized();
|
||||
|
||||
mark(f1) = true;
|
||||
d.push_back(f1);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// everything should be marked
|
||||
for (int i=0; i<F.rows(); i++)
|
||||
{
|
||||
assert(mark(i));
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
template <typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE void igl::comb_line_field(const Eigen::MatrixBase<DerivedV> &V,
|
||||
const Eigen::MatrixBase<DerivedF> &F,
|
||||
const Eigen::MatrixBase<DerivedV> &PD1,
|
||||
Eigen::PlainObjectBase<DerivedV> &PD1out)
|
||||
{
|
||||
igl::CombLine<DerivedV, DerivedF> cmb(V, F, PD1);
|
||||
cmb.comb(PD1out);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
#endif
|
||||
@@ -1,99 +0,0 @@
|
||||
// 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 "combine.h"
|
||||
#include <cassert>
|
||||
|
||||
template <
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVsizes,
|
||||
typename DerivedFsizes>
|
||||
IGL_INLINE void igl::combine(
|
||||
const std::vector<DerivedVV> & VV,
|
||||
const std::vector<DerivedFF> & FF,
|
||||
Eigen::PlainObjectBase<DerivedV> & V,
|
||||
Eigen::PlainObjectBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedVsizes> & Vsizes,
|
||||
Eigen::PlainObjectBase<DerivedFsizes> & Fsizes)
|
||||
{
|
||||
assert(VV.size() == FF.size() &&
|
||||
"Lists of verex lists and face lists should be same size");
|
||||
Vsizes.resize(VV.size());
|
||||
Fsizes.resize(FF.size());
|
||||
// Dimension of vertex positions
|
||||
const int dim = VV.size() > 0 ? VV[0].cols() : 0;
|
||||
// Simplex/element size
|
||||
const int ss = FF.size() > 0 ? FF[0].cols() : 0;
|
||||
int n = 0;
|
||||
int m = 0;
|
||||
for(int i = 0;i<VV.size();i++)
|
||||
{
|
||||
const auto & Vi = VV[i];
|
||||
const auto & Fi = FF[i];
|
||||
Vsizes(i) = Vi.rows();
|
||||
n+=Vi.rows();
|
||||
assert((Vi.size()==0 || dim == Vi.cols()) && "All vertex lists should have same #columns");
|
||||
Fsizes(i) = Fi.rows();
|
||||
m+=Fi.rows();
|
||||
assert((Fi.size()==0 || ss == Fi.cols()) && "All face lists should have same #columns");
|
||||
}
|
||||
V.resize(n,dim);
|
||||
F.resize(m,ss);
|
||||
{
|
||||
int kv = 0;
|
||||
int kf = 0;
|
||||
for(int i = 0;i<VV.size();i++)
|
||||
{
|
||||
const auto & Vi = VV[i];
|
||||
const int ni = Vi.rows();
|
||||
const auto & Fi = FF[i];
|
||||
const int mi = Fi.rows();
|
||||
if(Fi.size() >0)
|
||||
{
|
||||
F.block(kf,0,mi,ss) = Fi.array()+kv;
|
||||
}
|
||||
kf+=mi;
|
||||
if(Vi.size() >0)
|
||||
{
|
||||
V.block(kv,0,ni,dim) = Vi;
|
||||
}
|
||||
kv+=ni;
|
||||
}
|
||||
assert(kv == V.rows());
|
||||
assert(kf == F.rows());
|
||||
}
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedV,
|
||||
typename DerivedF>
|
||||
IGL_INLINE void igl::combine(
|
||||
const std::vector<DerivedVV> & VV,
|
||||
const std::vector<DerivedFF> & FF,
|
||||
Eigen::PlainObjectBase<DerivedV> & V,
|
||||
Eigen::PlainObjectBase<DerivedF> & F)
|
||||
{
|
||||
Eigen::VectorXi Vsizes,Fsizes;
|
||||
return igl::combine(VV,FF,V,F,Vsizes,Fsizes);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::combine<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::vector<Eigen::Matrix<float, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<float, -1, -1, 0, -1, -1> > > const&, std::vector<Eigen::Matrix<int, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<int, -1, -1, 0, -1, -1> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::combine<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1>, Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1> >(std::vector<Eigen::Matrix<double, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<double, -1, -1, 0, -1, -1> > > const&, std::vector<Eigen::Matrix<int, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<int, -1, -1, 0, -1, -1> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::combine<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::vector<Eigen::Matrix<double, -1, 3, 1, -1, 3>, std::allocator<Eigen::Matrix<double, -1, 3, 1, -1, 3> > > const&, std::vector<Eigen::Matrix<int, -1, 3, 1, -1, 3>, std::allocator<Eigen::Matrix<int, -1, 3, 1, -1, 3> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
|
||||
template void igl::combine<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::vector<Eigen::Matrix<double, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<double, -1, -1, 0, -1, -1> > > const&, std::vector<Eigen::Matrix<int, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<int, -1, -1, 0, -1, -1> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
#ifdef WIN32
|
||||
template void igl::combine<Eigen::Matrix<double,-1,-1,0,-1,-1>, Eigen::Matrix<int,-1,-1,0,-1,-1>,Eigen::Matrix<double,-1,-1,0,-1,-1>,Eigen::Matrix<int,-1,-1,0,-1,-1>,Eigen::Matrix<unsigned __int64,-1,1,0,-1,1>,Eigen::Matrix<unsigned __int64,-1,1,0,-1,1> >(class std::vector<Eigen::Matrix<double,-1,-1,0,-1,-1>,class std::allocator<Eigen::Matrix<double,-1,-1,0,-1,-1> > > const &,class std::vector<Eigen::Matrix<int,-1,-1,0,-1,-1>,class std::allocator<Eigen::Matrix<int,-1,-1,0,-1,-1> > > const &,Eigen::PlainObjectBase<Eigen::Matrix<double,-1,-1,0,-1,-1> > &,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,-1,0,-1,-1> > &,Eigen::PlainObjectBase<Eigen::Matrix<unsigned __int64,-1,1,0,-1,1> > &,Eigen::PlainObjectBase<Eigen::Matrix<unsigned __int64,-1,1,0,-1,1> > &);
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,86 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@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/.
|
||||
|
||||
#ifdef WIN32
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
#include <cmath>
|
||||
|
||||
#include "compute_frame_field_bisectors.h"
|
||||
#include "igl/local_basis.h"
|
||||
#include "PI.h"
|
||||
|
||||
template <typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE void igl::compute_frame_field_bisectors(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedV>& B1,
|
||||
const Eigen::MatrixBase<DerivedV>& B2,
|
||||
const Eigen::MatrixBase<DerivedV>& PD1,
|
||||
const Eigen::MatrixBase<DerivedV>& PD2,
|
||||
Eigen::PlainObjectBase<DerivedV>& BIS1,
|
||||
Eigen::PlainObjectBase<DerivedV>& BIS2)
|
||||
{
|
||||
BIS1.resize(PD1.rows(),3);
|
||||
BIS2.resize(PD1.rows(),3);
|
||||
|
||||
for (unsigned i=0; i<PD1.rows();++i)
|
||||
{
|
||||
// project onto the tangent plane and convert to angle
|
||||
// Convert to angle
|
||||
double a1 = atan2(B2.row(i).dot(PD1.row(i)),B1.row(i).dot(PD1.row(i)));
|
||||
//make it positive by adding some multiple of 2pi
|
||||
a1 += std::ceil (std::max(0., -a1) / (igl::PI*2.)) * (igl::PI*2.);
|
||||
//take modulo 2pi
|
||||
a1 = fmod(a1, (igl::PI*2.));
|
||||
double a2 = atan2(B2.row(i).dot(PD2.row(i)),B1.row(i).dot(PD2.row(i)));
|
||||
//make it positive by adding some multiple of 2pi
|
||||
a2 += std::ceil (std::max(0., -a2) / (igl::PI*2.)) * (igl::PI*2.);
|
||||
//take modulo 2pi
|
||||
a2 = fmod(a2, (igl::PI*2.));
|
||||
|
||||
double b1 = (a1+a2)/2.0;
|
||||
//make it positive by adding some multiple of 2pi
|
||||
b1 += std::ceil (std::max(0., -b1) / (igl::PI*2.)) * (igl::PI*2.);
|
||||
//take modulo 2pi
|
||||
b1 = fmod(b1, (igl::PI*2.));
|
||||
|
||||
double b2 = b1+(igl::PI/2.);
|
||||
//make it positive by adding some multiple of 2pi
|
||||
b2 += std::ceil (std::max(0., -b2) / (igl::PI*2.)) * (igl::PI*2.);
|
||||
//take modulo 2pi
|
||||
b2 = fmod(b2, (igl::PI*2.));
|
||||
|
||||
BIS1.row(i) = cos(b1) * B1.row(i) + sin(b1) * B2.row(i);
|
||||
BIS2.row(i) = cos(b2) * B1.row(i) + sin(b2) * B2.row(i);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
template <typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE void igl::compute_frame_field_bisectors(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedV>& PD1,
|
||||
const Eigen::MatrixBase<DerivedV>& PD2,
|
||||
Eigen::PlainObjectBase<DerivedV>& BIS1,
|
||||
Eigen::PlainObjectBase<DerivedV>& BIS2)
|
||||
{
|
||||
DerivedV B1, B2, B3;
|
||||
igl::local_basis(V,F,B1,B2,B3);
|
||||
|
||||
compute_frame_field_bisectors( V, F, B1, B2, PD1, PD2, BIS1, BIS2);
|
||||
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::compute_frame_field_bisectors<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::compute_frame_field_bisectors<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::compute_frame_field_bisectors<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -1,55 +0,0 @@
|
||||
// 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 "connect_boundary_to_infinity.h"
|
||||
#include "boundary_facets.h"
|
||||
|
||||
template <typename DerivedF, typename DerivedFO>
|
||||
IGL_INLINE void igl::connect_boundary_to_infinity(
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedFO> & FO)
|
||||
{
|
||||
return connect_boundary_to_infinity(F,F.maxCoeff(),FO);
|
||||
}
|
||||
template <typename DerivedF, typename DerivedFO>
|
||||
IGL_INLINE void igl::connect_boundary_to_infinity(
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const typename DerivedF::Scalar inf_index,
|
||||
Eigen::PlainObjectBase<DerivedFO> & FO)
|
||||
{
|
||||
// Determine boundary edges
|
||||
Eigen::Matrix<typename DerivedFO::Scalar,Eigen::Dynamic,Eigen::Dynamic> O;
|
||||
boundary_facets(F,O);
|
||||
FO.resize(F.rows()+O.rows(),F.cols());
|
||||
typedef Eigen::Matrix<typename DerivedFO::Scalar,Eigen::Dynamic,1> VectorXI;
|
||||
FO.topLeftCorner(F.rows(),F.cols()) = F;
|
||||
FO.bottomLeftCorner(O.rows(),O.cols()) = O.rowwise().reverse();
|
||||
FO.bottomRightCorner(O.rows(),1).setConstant(inf_index);
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVO,
|
||||
typename DerivedFO>
|
||||
IGL_INLINE void igl::connect_boundary_to_infinity(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedVO> & VO,
|
||||
Eigen::PlainObjectBase<DerivedFO> & FO)
|
||||
{
|
||||
typename DerivedV::Index inf_index = V.rows();
|
||||
connect_boundary_to_infinity(F,inf_index,FO);
|
||||
VO.resize(V.rows()+1,V.cols());
|
||||
VO.topLeftCorner(V.rows(),V.cols()) = V;
|
||||
auto inf = std::numeric_limits<typename DerivedVO::Scalar>::infinity();
|
||||
VO.row(V.rows()).setConstant(inf);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
template void igl::connect_boundary_to_infinity<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -1,63 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 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 "connected_components.h"
|
||||
#include <queue>
|
||||
|
||||
template < typename Atype, typename DerivedC, typename DerivedK>
|
||||
IGL_INLINE int igl::connected_components(
|
||||
const Eigen::SparseMatrix<Atype> & A,
|
||||
Eigen::PlainObjectBase<DerivedC> & C,
|
||||
Eigen::PlainObjectBase<DerivedK> & K)
|
||||
{
|
||||
typedef typename Eigen::SparseMatrix<Atype>::Index Index;
|
||||
const auto m = A.rows();
|
||||
assert(A.cols() == A.rows() && "A should be square");
|
||||
// 1.1 sec
|
||||
// m means not yet visited
|
||||
C.setConstant(m,1,m);
|
||||
// Could use amortized dynamic array but didn't see real win.
|
||||
K.setZero(m,1);
|
||||
typename DerivedC::Scalar c = 0;
|
||||
for(Eigen::Index f = 0;f<m;f++)
|
||||
{
|
||||
// already seen
|
||||
if(C(f)<m) continue;
|
||||
// start bfs
|
||||
std::queue<Index> Q;
|
||||
Q.push(f);
|
||||
while(!Q.empty())
|
||||
{
|
||||
const Index g = Q.front();
|
||||
Q.pop();
|
||||
// already seen
|
||||
if(C(g)<m) continue;
|
||||
// see it
|
||||
C(g) = c;
|
||||
K(c)++;
|
||||
for(typename Eigen::SparseMatrix<Atype>::InnerIterator it (A,g); it; ++it)
|
||||
{
|
||||
const Index n = it.index();
|
||||
// already seen
|
||||
if(C(n)<m) continue;
|
||||
Q.push(n);
|
||||
}
|
||||
}
|
||||
c++;
|
||||
}
|
||||
K.conservativeResize(c,1);
|
||||
return c;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template int igl::connected_components<bool, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<bool, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template int igl::connected_components<int, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<int, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
@@ -1,175 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@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_COPYLEFT_CGAL_BINARY_WINDING_NUMBER_OPERATIONS_H
|
||||
#define IGL_COPYLEFT_CGAL_BINARY_WINDING_NUMBER_OPERATIONS_H
|
||||
|
||||
#include <stdexcept>
|
||||
#include "../../igl_inline.h"
|
||||
#include "../../MeshBooleanType.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
// TODO: This is not written according to libigl style. These should be
|
||||
// function handles.
|
||||
//
|
||||
// Why is this templated on DerivedW
|
||||
//
|
||||
// These are all generalized to n-ary operations
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
/// Binary winding number operations
|
||||
template <igl::MeshBooleanType Op>
|
||||
class BinaryWindingNumberOperations {
|
||||
public:
|
||||
template<typename DerivedW>
|
||||
typename DerivedW::Scalar operator()(
|
||||
const Eigen::PlainObjectBase<DerivedW>& /*win_nums*/) const {
|
||||
throw (std::runtime_error("not implemented!"));
|
||||
}
|
||||
};
|
||||
|
||||
/// A ∪ B ∪ ... ∪ Z
|
||||
template <>
|
||||
class BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_UNION> {
|
||||
public:
|
||||
template<typename DerivedW>
|
||||
typename DerivedW::Scalar operator()(
|
||||
const Eigen::PlainObjectBase<DerivedW>& win_nums) const
|
||||
{
|
||||
for(int i = 0;i<win_nums.size();i++)
|
||||
{
|
||||
if(win_nums(i) > 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/// A ∩ B ∩ ... ∩ Z
|
||||
template <>
|
||||
class BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_INTERSECT> {
|
||||
public:
|
||||
template<typename DerivedW>
|
||||
typename DerivedW::Scalar operator()(
|
||||
const Eigen::PlainObjectBase<DerivedW>& win_nums) const
|
||||
{
|
||||
for(int i = 0;i<win_nums.size();i++)
|
||||
{
|
||||
if(win_nums(i)<=0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/// A \ B \ ... \ Z = A \ (B ∪ ... ∪ Z)
|
||||
template <>
|
||||
class BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_MINUS> {
|
||||
public:
|
||||
template<typename DerivedW>
|
||||
typename DerivedW::Scalar operator()(
|
||||
const Eigen::PlainObjectBase<DerivedW>& win_nums) const
|
||||
{
|
||||
assert(win_nums.size()>1);
|
||||
// Union of objects 1 through n-1
|
||||
bool union_rest = false;
|
||||
for(int i = 1;i<win_nums.size();i++)
|
||||
{
|
||||
union_rest = union_rest || win_nums(i) > 0;
|
||||
if(union_rest) break;
|
||||
}
|
||||
// Must be in object 0 and not in union of objects 1 through n-1
|
||||
return win_nums(0) > 0 && !union_rest;
|
||||
}
|
||||
};
|
||||
|
||||
/// A ∆ B ∆ ... ∆ Z (equivalent to set inside odd number of objects)
|
||||
template <>
|
||||
class BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_XOR> {
|
||||
public:
|
||||
template<typename DerivedW>
|
||||
typename DerivedW::Scalar operator()(
|
||||
const Eigen::PlainObjectBase<DerivedW>& win_nums) const
|
||||
{
|
||||
// If inside an odd number of objects
|
||||
int count = 0;
|
||||
for(int i = 0;i<win_nums.size();i++)
|
||||
{
|
||||
if(win_nums(i) > 0) count++;
|
||||
}
|
||||
return count % 2 == 1;
|
||||
}
|
||||
};
|
||||
|
||||
/// Resolve all intersections without removing non-coplanar faces
|
||||
template <>
|
||||
class BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_RESOLVE> {
|
||||
public:
|
||||
template<typename DerivedW>
|
||||
typename DerivedW::Scalar operator()(
|
||||
const Eigen::PlainObjectBase<DerivedW>& /*win_nums*/) const {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
typedef BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_UNION> BinaryUnion;
|
||||
typedef BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_INTERSECT> BinaryIntersect;
|
||||
typedef BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_MINUS> BinaryMinus;
|
||||
typedef BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_XOR> BinaryXor;
|
||||
typedef BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_RESOLVE> BinaryResolve;
|
||||
|
||||
/// Types of Keep policies
|
||||
enum KeeperType {
|
||||
/// Keep only inside
|
||||
KEEP_INSIDE,
|
||||
/// Keep everything
|
||||
KEEP_ALL
|
||||
};
|
||||
|
||||
/// Filter winding numbers according to keep policy
|
||||
template<KeeperType T>
|
||||
class WindingNumberFilter {
|
||||
public:
|
||||
template<typename DerivedW>
|
||||
short operator()(
|
||||
const Eigen::PlainObjectBase<DerivedW>& /*win_nums*/) const {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
};
|
||||
|
||||
/// Keep inside policy
|
||||
template<>
|
||||
class WindingNumberFilter<KEEP_INSIDE> {
|
||||
public:
|
||||
template<typename T>
|
||||
short operator()(T out_w, T in_w) const {
|
||||
if (in_w > 0 && out_w <= 0) return 1;
|
||||
else if (in_w <= 0 && out_w > 0) return -1;
|
||||
else return 0;
|
||||
}
|
||||
};
|
||||
|
||||
/// Keep all policy
|
||||
template<>
|
||||
class WindingNumberFilter<KEEP_ALL> {
|
||||
public:
|
||||
template<typename T>
|
||||
short operator()(T /*out_w*/, T /*in_w*/) const {
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
using KeepInside = WindingNumberFilter<KEEP_INSIDE>;
|
||||
using KeepAll = WindingNumberFilter<KEEP_ALL>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,187 +0,0 @@
|
||||
// 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_COPYLEFT_CGAL_CSG_TREE_H
|
||||
#define IGL_COPYLEFT_CGAL_CSG_TREE_H
|
||||
|
||||
#include "../../MeshBooleanType.h"
|
||||
#include "string_to_mesh_boolean_type.h"
|
||||
#include "mesh_boolean.h"
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/number_utils.h>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
/// Class for defining and computing a constructive solid geometry result
|
||||
/// out of a tree of boolean operations on "solid" triangle meshes.
|
||||
///
|
||||
class CSGTree
|
||||
{
|
||||
public:
|
||||
typedef CGAL::Epeck::FT ExactScalar;
|
||||
//typedef Eigen::PlainObjectBase<DerivedF> POBF;
|
||||
typedef Eigen::MatrixXi POBF;
|
||||
typedef Eigen::Matrix<ExactScalar,Eigen::Dynamic,3> MatrixX3E;
|
||||
typedef Eigen::VectorXi VectorJ;
|
||||
private:
|
||||
/// Resulting mesh vertex positions
|
||||
MatrixX3E m_V;
|
||||
/// Resulting mesh face indices into V
|
||||
POBF m_F;
|
||||
/// Birth index of each face in resulting mesh. Birth index is the index
|
||||
VectorJ m_J;
|
||||
/// Number of birth faces in A + those in B. I.e. sum of original "leaf"
|
||||
/// faces involved in result.
|
||||
size_t m_number_of_birth_faces;
|
||||
public:
|
||||
CSGTree()
|
||||
{
|
||||
}
|
||||
//typedef Eigen::MatrixXd MatrixX3E;
|
||||
//typedef Eigen::MatrixXi POBF;
|
||||
// http://stackoverflow.com/a/3279550/148668
|
||||
CSGTree(const CSGTree & other)
|
||||
:
|
||||
// copy things
|
||||
m_V(other.m_V),
|
||||
// This is an issue if m_F is templated
|
||||
// https://forum.kde.org/viewtopic.php?f=74&t=128414
|
||||
m_F(other.m_F),
|
||||
m_J(other.m_J),
|
||||
m_number_of_birth_faces(other.m_number_of_birth_faces)
|
||||
{
|
||||
}
|
||||
// copy-swap idiom
|
||||
friend void swap(CSGTree& first, CSGTree& second)
|
||||
{
|
||||
using std::swap;
|
||||
// swap things
|
||||
swap(first.m_V,second.m_V);
|
||||
// This is an issue if m_F is templated, similar to
|
||||
// https://forum.kde.org/viewtopic.php?f=74&t=128414
|
||||
swap(first.m_F,second.m_F);
|
||||
swap(first.m_J,second.m_J);
|
||||
swap(first.m_number_of_birth_faces,second.m_number_of_birth_faces);
|
||||
}
|
||||
// Pass-by-value (aka copy)
|
||||
CSGTree& operator=(CSGTree other)
|
||||
{
|
||||
swap(*this,other);
|
||||
return *this;
|
||||
}
|
||||
CSGTree(CSGTree&& other):
|
||||
// initialize via default constructor
|
||||
CSGTree()
|
||||
{
|
||||
swap(*this,other);
|
||||
}
|
||||
/// Construct and compute a boolean operation on existing CSGTree nodes.
|
||||
///
|
||||
/// @param[in] A Solid result of previous CSG operation (or identity, see below)
|
||||
/// @param[in] B Solid result of previous CSG operation (or identity, see below)
|
||||
/// @param[in] type type of mesh boolean to compute
|
||||
CSGTree(
|
||||
const CSGTree & A,
|
||||
const CSGTree & B,
|
||||
const MeshBooleanType & type)
|
||||
{
|
||||
// conduct boolean operation
|
||||
mesh_boolean(A.V(),A.F(),B.V(),B.F(),type,m_V,m_F,m_J);
|
||||
// reindex m_J
|
||||
std::for_each(m_J.data(),m_J.data()+m_J.size(),
|
||||
[&](typename VectorJ::Scalar & j) -> void
|
||||
{
|
||||
if(j < A.F().rows())
|
||||
{
|
||||
j = A.J()(j);
|
||||
}else
|
||||
{
|
||||
assert(j<(A.F().rows()+B.F().rows()));
|
||||
j = A.number_of_birth_faces()+(B.J()(j-A.F().rows()));
|
||||
}
|
||||
});
|
||||
m_number_of_birth_faces =
|
||||
A.number_of_birth_faces() + B.number_of_birth_faces();
|
||||
}
|
||||
/// \overload
|
||||
CSGTree(
|
||||
const CSGTree & A,
|
||||
const CSGTree & B,
|
||||
const std::string & s):
|
||||
CSGTree(A,B,string_to_mesh_boolean_type(s))
|
||||
{
|
||||
// do nothing (all done in constructor).
|
||||
}
|
||||
/// "Leaf" node with identity operation on assumed "solid" mesh (V,F)
|
||||
///
|
||||
/// @param[in] V #V by 3 list of mesh vertices (in any precision, will be
|
||||
/// converted to exact)
|
||||
/// @param[in] F #F by 3 list of mesh face indices into V
|
||||
template <typename DerivedV>
|
||||
CSGTree(const Eigen::PlainObjectBase<DerivedV> & V, const POBF & F)//:
|
||||
// Possible Eigen bug:
|
||||
// https://forum.kde.org/viewtopic.php?f=74&t=128414
|
||||
//m_V(V.template cast<ExactScalar>()),m_F(F)
|
||||
{
|
||||
m_V = V.template cast<ExactScalar>();
|
||||
m_F = F;
|
||||
// number of faces
|
||||
m_number_of_birth_faces = m_F.rows();
|
||||
// identity birth index
|
||||
m_J = VectorJ::LinSpaced(
|
||||
m_number_of_birth_faces,0,m_number_of_birth_faces-1);
|
||||
}
|
||||
// Returns reference to resulting mesh vertices m_V in exact scalar
|
||||
// representation
|
||||
const MatrixX3E & V() const
|
||||
{
|
||||
return m_V;
|
||||
}
|
||||
// Returns mesh vertices in the desired output type, casting when
|
||||
// appropriate to floating precision.
|
||||
template <typename DerivedV>
|
||||
DerivedV cast_V() const
|
||||
{
|
||||
DerivedV dV;
|
||||
dV.resize(m_V.rows(),m_V.cols());
|
||||
for(int i = 0;i<m_V.rows();i++)
|
||||
{
|
||||
for(int j = 0;j<m_V.cols();j++)
|
||||
{
|
||||
dV(i,j) = CGAL::to_double(m_V(i,j));
|
||||
}
|
||||
}
|
||||
return dV;
|
||||
}
|
||||
// Returns reference to resulting mesh faces m_F
|
||||
const POBF & F() const
|
||||
{
|
||||
return m_F;
|
||||
}
|
||||
// Returns reference to "birth parents" indices into [F1;F2;...;Fn]
|
||||
// where F1, ... , Fn are the face lists of the leaf ("original") input
|
||||
// meshes.
|
||||
const VectorJ & J() const
|
||||
{
|
||||
return m_J;
|
||||
}
|
||||
// The number of leaf faces = #F1 + #F2 + ... + #Fn
|
||||
const size_t & number_of_birth_faces() const
|
||||
{
|
||||
return m_number_of_birth_faces;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,48 +0,0 @@
|
||||
// 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_COPYLEFT_CGAL_REMESH_SELF_INTERSECTIONS_PARAM_H
|
||||
#define IGL_COPYLEFT_CGAL_REMESH_SELF_INTERSECTIONS_PARAM_H
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
/// Parameters for SelfIntersectMesh, remesh_self_intersections and
|
||||
/// remesh_intersections, and intersect_other
|
||||
///
|
||||
struct RemeshSelfIntersectionsParam
|
||||
{
|
||||
/// avoid constructing intersections results when possible
|
||||
bool detect_only;
|
||||
/// return after detecting the first intersection (if first_only==true,
|
||||
/// then detect_only should also be true)
|
||||
bool first_only;
|
||||
/// whether to stitch all resulting constructed elements into a
|
||||
/// (non-manifold) mesh
|
||||
bool stitch_all;
|
||||
/// whether to use slow and more precise rounding (see assign_scalar)
|
||||
bool slow_and_more_precise_rounding;
|
||||
inline RemeshSelfIntersectionsParam(
|
||||
bool _detect_only=false,
|
||||
bool _first_only=false,
|
||||
bool _stitch_all=false,
|
||||
bool _slow_and_more_precise_rounding=false
|
||||
):
|
||||
detect_only(_detect_only),
|
||||
first_only(_first_only),
|
||||
stitch_all(_stitch_all),
|
||||
slow_and_more_precise_rounding(_slow_and_more_precise_rounding)
|
||||
{};
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,947 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 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_COPYLEFT_CGAL_SELFINTERSECTMESH_H
|
||||
#define IGL_COPYLEFT_CGAL_SELFINTERSECTMESH_H
|
||||
|
||||
#include "CGAL_includes.hpp"
|
||||
#include "RemeshSelfIntersectionsParam.h"
|
||||
#include "../../unique.h"
|
||||
#include "../../default_num_threads.h"
|
||||
|
||||
#include <Eigen/Dense>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <cstdio>
|
||||
|
||||
//#define IGL_SELFINTERSECTMESH_TIMING
|
||||
#ifndef IGL_FIRST_HIT_EXCEPTION
|
||||
#define IGL_FIRST_HIT_EXCEPTION 10
|
||||
#endif
|
||||
|
||||
// The easiest way to keep track of everything is to use a class
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
/// Class for computing the self-intersections of a mesh
|
||||
///
|
||||
/// @tparam Kernel is a CGAL kernel like:
|
||||
/// CGAL::Exact_predicates_inexact_constructions_kernel
|
||||
/// or
|
||||
/// CGAL::Exact_predicates_exact_constructions_kernel
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedIF,
|
||||
typename DerivedJ,
|
||||
typename DerivedIM>
|
||||
class SelfIntersectMesh
|
||||
{
|
||||
typedef
|
||||
SelfIntersectMesh<
|
||||
Kernel,
|
||||
DerivedV,
|
||||
DerivedF,
|
||||
DerivedVV,
|
||||
DerivedFF,
|
||||
DerivedIF,
|
||||
DerivedJ,
|
||||
DerivedIM> Self;
|
||||
public:
|
||||
// 3D Primitives
|
||||
typedef CGAL::Point_3<Kernel> Point_3;
|
||||
typedef CGAL::Segment_3<Kernel> Segment_3;
|
||||
typedef CGAL::Triangle_3<Kernel> Triangle_3;
|
||||
typedef CGAL::Plane_3<Kernel> Plane_3;
|
||||
typedef CGAL::Tetrahedron_3<Kernel> Tetrahedron_3;
|
||||
// 2D Primitives
|
||||
typedef CGAL::Point_2<Kernel> Point_2;
|
||||
typedef CGAL::Segment_2<Kernel> Segment_2;
|
||||
typedef CGAL::Triangle_2<Kernel> Triangle_2;
|
||||
// 2D Constrained Delaunay Triangulation types
|
||||
typedef CGAL::Exact_intersections_tag Itag;
|
||||
// Axis-align boxes for all-pairs self-intersection detection
|
||||
typedef std::vector<Triangle_3> Triangles;
|
||||
typedef typename Triangles::iterator TrianglesIterator;
|
||||
typedef typename Triangles::const_iterator TrianglesConstIterator;
|
||||
typedef
|
||||
CGAL::Box_intersection_d::Box_with_handle_d<double,3,TrianglesIterator>
|
||||
Box;
|
||||
|
||||
// Input mesh
|
||||
const Eigen::MatrixBase<DerivedV> & V;
|
||||
const Eigen::MatrixBase<DerivedF> & F;
|
||||
// Number of self-intersecting triangle pairs
|
||||
typedef typename DerivedF::Index Index;
|
||||
Index count;
|
||||
typedef std::vector<std::pair<Index, CGAL::Object>> ObjectList;
|
||||
// Using a vector here makes this **not** output sensitive
|
||||
Triangles T;
|
||||
typedef std::vector<Index> IndexList;
|
||||
IndexList lIF;
|
||||
// #F-long list of faces with intersections mapping to the order in
|
||||
// which they were first found
|
||||
std::map<Index,ObjectList> offending;
|
||||
// Make a short name for the edge map's key
|
||||
typedef std::pair<Index,Index> EMK;
|
||||
// Make a short name for the type stored at each edge, the edge map's
|
||||
// value
|
||||
typedef std::vector<Index> EMV;
|
||||
// Make a short name for the edge map
|
||||
typedef std::map<EMK,EMV> EdgeMap;
|
||||
// Maps edges of offending faces to all incident offending faces
|
||||
std::vector<std::pair<TrianglesIterator, TrianglesIterator> >
|
||||
candidate_triangle_pairs;
|
||||
|
||||
public:
|
||||
RemeshSelfIntersectionsParam params;
|
||||
public:
|
||||
/// Constructs (VV,FF) a new mesh with self-intersections of (V,F)
|
||||
/// subdivided
|
||||
///
|
||||
/// @param[in] V #V by 3 list of vertex positions
|
||||
/// @param[in] F #F by 3 list of triangle indices into V
|
||||
/// @param[in] params parameters
|
||||
/// @param[out] VV #VV by 3 list of vertex positions
|
||||
/// @param[out] FF #FF by 3 list of triangle indices into VV
|
||||
/// @param[out] IF #IF by 2 list of edge indices into VV
|
||||
/// @param[out] J #F list of indices into FF of birth parents
|
||||
/// @param[out] IM #VV list of indices into V of birth parents
|
||||
///
|
||||
///
|
||||
/// \see remesh_self_intersections.h
|
||||
inline SelfIntersectMesh(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const RemeshSelfIntersectionsParam & params,
|
||||
Eigen::PlainObjectBase<DerivedVV> & VV,
|
||||
Eigen::PlainObjectBase<DerivedFF> & FF,
|
||||
Eigen::PlainObjectBase<DerivedIF> & IF,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J,
|
||||
Eigen::PlainObjectBase<DerivedIM> & IM);
|
||||
private:
|
||||
/// Helper function to mark a face as offensive
|
||||
///
|
||||
/// @param[in] f index of face in F
|
||||
inline void mark_offensive(const Index f);
|
||||
/// Helper function to count intersections between faces
|
||||
///
|
||||
/// @param[in] fa index of face A in F
|
||||
/// @param[in] fb index of face B in F
|
||||
inline void count_intersection( const Index fa, const Index fb);
|
||||
/// Helper function for box_intersect. Intersect two triangles A and B,
|
||||
/// append the intersection object (point,segment,triangle) to a running
|
||||
/// list for A and B
|
||||
///
|
||||
/// @param[in] A triangle in 3D
|
||||
/// @param[in] B triangle in 3D
|
||||
/// @param[in] fa index of A in F (and key into offending)
|
||||
/// @param[in] fb index of B in F (and key into offending)
|
||||
/// @return true only if A intersects B
|
||||
///
|
||||
inline bool intersect(
|
||||
const Triangle_3 & A,
|
||||
const Triangle_3 & B,
|
||||
const Index fa,
|
||||
const Index fb);
|
||||
/// Helper function for box_intersect. In the case where A and B have
|
||||
/// already been identified to share a vertex, then we only want to
|
||||
/// add possible segment intersections. Assumes truly duplicate
|
||||
/// triangles are not given as input
|
||||
///
|
||||
/// @param[in] A triangle in 3D
|
||||
/// @param[in] B triangle in 3D
|
||||
/// @param[in] fa index of A in F (and key into offending)
|
||||
/// @param[in] fb index of B in F (and key into offending)
|
||||
/// @param[in] va index of shared vertex in A (and key into offending)
|
||||
/// @param[in] vb index of shared vertex in B (and key into offending)
|
||||
/// @return true if intersection (besides shared point)
|
||||
///
|
||||
inline bool single_shared_vertex(
|
||||
const Triangle_3 & A,
|
||||
const Triangle_3 & B,
|
||||
const Index fa,
|
||||
const Index fb,
|
||||
const Index va,
|
||||
const Index vb);
|
||||
//// Helper handling one direction
|
||||
///
|
||||
/// @param[in] A triangle in 3D
|
||||
/// @param[in] B triangle in 3D
|
||||
/// @param[in] fa index of A in F (and key into offending)
|
||||
/// @param[in] fb index of B in F (and key into offending)
|
||||
/// @param[in] va index of shared vertex in A (and key into offending)
|
||||
/// @return true if intersection (besides shared point)
|
||||
inline bool single_shared_vertex(
|
||||
const Triangle_3 & A,
|
||||
const Triangle_3 & B,
|
||||
const Index fa,
|
||||
const Index fb,
|
||||
const Index va);
|
||||
/// Helper function for box_intersect. In the case where A and B have
|
||||
/// already been identified to share two vertices, then we only want
|
||||
/// to add a possible coplanar (Triangle) intersection. Assumes truly
|
||||
/// degenerate facets are not givin as input.
|
||||
///
|
||||
/// @param[in] A triangle in 3D
|
||||
/// @param[in] B triangle in 3D
|
||||
/// @param[in] fa index of A in F (and key into offending)
|
||||
/// @param[in] fb index of B in F (and key into offending)
|
||||
/// @param[in] shared list of pairs of indices of shared vertices
|
||||
/// @return true if intersection (besides shared point)
|
||||
inline bool double_shared_vertex(
|
||||
const Triangle_3 & A,
|
||||
const Triangle_3 & B,
|
||||
const Index fa,
|
||||
const Index fb,
|
||||
const std::vector<std::pair<Index,Index> > shared);
|
||||
|
||||
public:
|
||||
/// Callback function called during box self intersections test. Means
|
||||
/// boxes a and b intersect. This method then checks if the triangles
|
||||
/// in each box intersect and if so, then processes the intersections
|
||||
///
|
||||
/// @param[in] a box containing a triangle
|
||||
/// @param[in] b box containing a triangle
|
||||
inline void box_intersect(const Box& a, const Box& b);
|
||||
/// Process all of the intersecting boxes
|
||||
inline void process_intersecting_boxes();
|
||||
public:
|
||||
// Getters:
|
||||
//const IndexList& get_lIF() const{ return lIF;}
|
||||
/// Static function that captures a SelfIntersectMesh instance to pass
|
||||
/// to cgal.
|
||||
/// @param[in] SIM pointer to SelfIntersectMesh instance
|
||||
/// @param[in] a box containing a triangle
|
||||
/// @param[in] b box containing a triangle
|
||||
static inline void box_intersect_static(
|
||||
SelfIntersectMesh * SIM,
|
||||
const Box &a,
|
||||
const Box &b);
|
||||
private:
|
||||
std::mutex m_offending_lock;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation
|
||||
|
||||
#include "mesh_to_cgal_triangle_list.h"
|
||||
#include "remesh_intersections.h"
|
||||
|
||||
#include "../../REDRUM.h"
|
||||
#include "../../get_seconds.h"
|
||||
#include "../../C_STR.h"
|
||||
|
||||
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
// References:
|
||||
// http://minregret.googlecode.com/svn/trunk/skyline/src/extern/CGAL-3.3.1/examples/Polyhedron/polyhedron_self_intersection.cpp
|
||||
// http://www.cgal.org/Manual/3.9/examples/Boolean_set_operations_2/do_intersect.cpp
|
||||
|
||||
// Q: Should we be using CGAL::Polyhedron_3?
|
||||
// A: No! Input is just a list of unoriented triangles. Polyhedron_3 requires
|
||||
// a 2-manifold.
|
||||
// A: But! It seems we could use CGAL::Triangulation_3. Though it won't be easy
|
||||
// to take advantage of functions like insert_in_facet because we want to
|
||||
// constrain segments. Hmmm. Actually Triangulation_3 doesn't look right...
|
||||
|
||||
// CGAL's box_self_intersection_d uses C-style function callbacks without
|
||||
// userdata. This is a leapfrog method for calling a member function. It should
|
||||
// be bound as if the prototype was:
|
||||
// static void box_intersect(const Box &a, const Box &b)
|
||||
// using boost:
|
||||
// boost::function<void(const Box &a,const Box &b)> cb
|
||||
// = boost::bind(&::box_intersect, this, _1,_2);
|
||||
//
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedIF,
|
||||
typename DerivedJ,
|
||||
typename DerivedIM>
|
||||
inline void igl::copyleft::cgal::SelfIntersectMesh<
|
||||
Kernel,
|
||||
DerivedV,
|
||||
DerivedF,
|
||||
DerivedVV,
|
||||
DerivedFF,
|
||||
DerivedIF,
|
||||
DerivedJ,
|
||||
DerivedIM>::box_intersect_static(
|
||||
Self * SIM,
|
||||
const typename Self::Box &a,
|
||||
const typename Self::Box &b)
|
||||
{
|
||||
SIM->box_intersect(a,b);
|
||||
}
|
||||
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedIF,
|
||||
typename DerivedJ,
|
||||
typename DerivedIM>
|
||||
inline igl::copyleft::cgal::SelfIntersectMesh<
|
||||
Kernel,
|
||||
DerivedV,
|
||||
DerivedF,
|
||||
DerivedVV,
|
||||
DerivedFF,
|
||||
DerivedIF,
|
||||
DerivedJ,
|
||||
DerivedIM>::SelfIntersectMesh(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const RemeshSelfIntersectionsParam & params,
|
||||
Eigen::PlainObjectBase<DerivedVV> & VV,
|
||||
Eigen::PlainObjectBase<DerivedFF> & FF,
|
||||
Eigen::PlainObjectBase<DerivedIF> & IF,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J,
|
||||
Eigen::PlainObjectBase<DerivedIM> & IM):
|
||||
V(V),
|
||||
F(F),
|
||||
count(0),
|
||||
T(),
|
||||
lIF(),
|
||||
offending(),
|
||||
params(params)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
|
||||
#ifdef IGL_SELFINTERSECTMESH_TIMING
|
||||
const auto & tictoc = []() -> double
|
||||
{
|
||||
static double t_start = igl::get_seconds();
|
||||
double diff = igl::get_seconds()-t_start;
|
||||
t_start += diff;
|
||||
return diff;
|
||||
};
|
||||
const auto log_time = [&](const std::string& label) -> void{
|
||||
printf("%50s: %0.5lf\n",
|
||||
C_STR("SelfIntersectMesh." << label),tictoc());
|
||||
};
|
||||
tictoc();
|
||||
#endif
|
||||
|
||||
// Compute and process self intersections
|
||||
mesh_to_cgal_triangle_list(V,F,T);
|
||||
#ifdef IGL_SELFINTERSECTMESH_TIMING
|
||||
log_time("convert_to_triangle_list");
|
||||
#endif
|
||||
// http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Box_intersection_d/Chapter_main.html#Section_63.5
|
||||
// Create the corresponding vector of bounding boxes
|
||||
std::vector<Box> boxes;
|
||||
boxes.reserve(T.size());
|
||||
for (
|
||||
TrianglesIterator tit = T.begin();
|
||||
tit != T.end();
|
||||
++tit)
|
||||
{
|
||||
if (!tit->is_degenerate())
|
||||
{
|
||||
boxes.push_back(Box(tit->bbox(), tit));
|
||||
}
|
||||
}
|
||||
// Leapfrog callback
|
||||
std::function<void(const Box &a,const Box &b)> cb =
|
||||
std::bind(&box_intersect_static, this,
|
||||
// Explicitly use std namespace to avoid confusion with boost (who puts
|
||||
// _1 etc. in global namespace)
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2);
|
||||
#ifdef IGL_SELFINTERSECTMESH_TIMING
|
||||
log_time("box_and_bind");
|
||||
#endif
|
||||
// Run the self intersection algorithm with all defaults
|
||||
CGAL::box_self_intersection_d(boxes.begin(), boxes.end(),cb);
|
||||
#ifdef IGL_SELFINTERSECTMESH_TIMING
|
||||
log_time("box_intersection_d");
|
||||
#endif
|
||||
try{
|
||||
process_intersecting_boxes();
|
||||
}catch(int e)
|
||||
{
|
||||
// Rethrow if not IGL_FIRST_HIT_EXCEPTION
|
||||
if(e != IGL_FIRST_HIT_EXCEPTION)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
// Otherwise just fall through
|
||||
}
|
||||
#ifdef IGL_SELFINTERSECTMESH_TIMING
|
||||
log_time("resolve_intersection");
|
||||
#endif
|
||||
|
||||
// Convert lIF to Eigen matrix
|
||||
assert(lIF.size()%2 == 0);
|
||||
IF.resize(lIF.size()/2,2);
|
||||
{
|
||||
Index i=0;
|
||||
for(
|
||||
typename IndexList::const_iterator ifit = lIF.begin();
|
||||
ifit!=lIF.end();
|
||||
)
|
||||
{
|
||||
IF(i,0) = (*ifit);
|
||||
ifit++;
|
||||
IF(i,1) = (*ifit);
|
||||
ifit++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
#ifdef IGL_SELFINTERSECTMESH_TIMING
|
||||
log_time("store_intersecting_face_pairs");
|
||||
#endif
|
||||
|
||||
if(params.detect_only)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
remesh_intersections(
|
||||
V,F,T,offending,
|
||||
params.stitch_all,params.slow_and_more_precise_rounding,VV,FF,J,IM);
|
||||
|
||||
#ifdef IGL_SELFINTERSECTMESH_TIMING
|
||||
log_time("remesh_intersection");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedIF,
|
||||
typename DerivedJ,
|
||||
typename DerivedIM>
|
||||
inline void igl::copyleft::cgal::SelfIntersectMesh<
|
||||
Kernel,
|
||||
DerivedV,
|
||||
DerivedF,
|
||||
DerivedVV,
|
||||
DerivedFF,
|
||||
DerivedIF,
|
||||
DerivedJ,
|
||||
DerivedIM>::mark_offensive(const Index f)
|
||||
{
|
||||
using namespace std;
|
||||
lIF.push_back(f);
|
||||
if(offending.count(f) == 0)
|
||||
{
|
||||
// first time marking, initialize with new id and empty list
|
||||
offending[f] = {};
|
||||
}
|
||||
}
|
||||
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedIF,
|
||||
typename DerivedJ,
|
||||
typename DerivedIM>
|
||||
inline void igl::copyleft::cgal::SelfIntersectMesh<
|
||||
Kernel,
|
||||
DerivedV,
|
||||
DerivedF,
|
||||
DerivedVV,
|
||||
DerivedFF,
|
||||
DerivedIF,
|
||||
DerivedJ,
|
||||
DerivedIM>::count_intersection(
|
||||
const Index fa,
|
||||
const Index fb)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(m_offending_lock);
|
||||
mark_offensive(fa);
|
||||
mark_offensive(fb);
|
||||
this->count++;
|
||||
// We found the first intersection
|
||||
if(params.first_only && this->count >= 1)
|
||||
{
|
||||
throw IGL_FIRST_HIT_EXCEPTION;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedIF,
|
||||
typename DerivedJ,
|
||||
typename DerivedIM>
|
||||
inline bool igl::copyleft::cgal::SelfIntersectMesh<
|
||||
Kernel,
|
||||
DerivedV,
|
||||
DerivedF,
|
||||
DerivedVV,
|
||||
DerivedFF,
|
||||
DerivedIF,
|
||||
DerivedJ,
|
||||
DerivedIM>::intersect(
|
||||
const Triangle_3 & A,
|
||||
const Triangle_3 & B,
|
||||
const Index fa,
|
||||
const Index fb)
|
||||
{
|
||||
// Determine whether there is an intersection
|
||||
if(!CGAL::do_intersect(A,B))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
count_intersection(fa,fb);
|
||||
if(!params.detect_only)
|
||||
{
|
||||
// Construct intersection
|
||||
CGAL::Object result = CGAL::intersection(A,B);
|
||||
// Could avoid this mutex if `offending` was per-thread and passed as input
|
||||
// reference.
|
||||
std::lock_guard<std::mutex> guard(m_offending_lock);
|
||||
offending[fa].push_back({fb, result});
|
||||
offending[fb].push_back({fa, result});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedIF,
|
||||
typename DerivedJ,
|
||||
typename DerivedIM>
|
||||
inline bool igl::copyleft::cgal::SelfIntersectMesh<
|
||||
Kernel,
|
||||
DerivedV,
|
||||
DerivedF,
|
||||
DerivedVV,
|
||||
DerivedFF,
|
||||
DerivedIF,
|
||||
DerivedJ,
|
||||
DerivedIM>::single_shared_vertex(
|
||||
const Triangle_3 & A,
|
||||
const Triangle_3 & B,
|
||||
const Index fa,
|
||||
const Index fb,
|
||||
const Index va,
|
||||
const Index vb)
|
||||
{
|
||||
if(single_shared_vertex(A,B,fa,fb,va))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return single_shared_vertex(B,A,fb,fa,vb);
|
||||
}
|
||||
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedIF,
|
||||
typename DerivedJ,
|
||||
typename DerivedIM>
|
||||
inline bool igl::copyleft::cgal::SelfIntersectMesh<
|
||||
Kernel,
|
||||
DerivedV,
|
||||
DerivedF,
|
||||
DerivedVV,
|
||||
DerivedFF,
|
||||
DerivedIF,
|
||||
DerivedJ,
|
||||
DerivedIM>::single_shared_vertex(
|
||||
const Triangle_3 & A,
|
||||
const Triangle_3 & B,
|
||||
const Index fa,
|
||||
const Index fb,
|
||||
const Index va)
|
||||
{
|
||||
// This was not a good idea. It will not handle coplanar triangles well.
|
||||
using namespace std;
|
||||
Segment_3 sa(
|
||||
A.vertex((va+1)%3),
|
||||
A.vertex((va+2)%3));
|
||||
|
||||
if(CGAL::do_intersect(sa,B))
|
||||
{
|
||||
// can't put count_intersection(fa,fb) here since we use intersect below
|
||||
// and then it will be counted twice.
|
||||
if(params.detect_only)
|
||||
{
|
||||
count_intersection(fa,fb);
|
||||
return true;
|
||||
}
|
||||
CGAL::Object result = CGAL::intersection(sa,B);
|
||||
if(const Point_3 * p = CGAL::object_cast<Point_3 >(&result))
|
||||
{
|
||||
// Single intersection --> segment from shared point to intersection
|
||||
CGAL::Object seg = CGAL::make_object(Segment_3(
|
||||
A.vertex(va),
|
||||
*p));
|
||||
count_intersection(fa,fb);
|
||||
std::lock_guard<std::mutex> guard(m_offending_lock);
|
||||
offending[fa].push_back({fb, seg});
|
||||
offending[fb].push_back({fa, seg});
|
||||
return true;
|
||||
}else if(CGAL::object_cast<Segment_3 >(&result))
|
||||
{
|
||||
// Need to do full test. Intersection could be a general poly.
|
||||
bool test = intersect(A,B,fa,fb);
|
||||
((void)test);
|
||||
assert(test && "intersect should agree with do_intersect");
|
||||
return true;
|
||||
}else
|
||||
{
|
||||
cerr<<REDRUM("Segment ∩ triangle neither point nor segment?")<<endl;
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedIF,
|
||||
typename DerivedJ,
|
||||
typename DerivedIM>
|
||||
inline bool igl::copyleft::cgal::SelfIntersectMesh<
|
||||
Kernel,
|
||||
DerivedV,
|
||||
DerivedF,
|
||||
DerivedVV,
|
||||
DerivedFF,
|
||||
DerivedIF,
|
||||
DerivedJ,
|
||||
DerivedIM>::double_shared_vertex(
|
||||
const Triangle_3 & A,
|
||||
const Triangle_3 & B,
|
||||
const Index fa,
|
||||
const Index fb,
|
||||
const std::vector<std::pair<Index,Index> > shared)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
auto opposite_vertex = [](const Index a0, const Index a1) {
|
||||
// get opposite index of A
|
||||
int a2=-1;
|
||||
for(int c=0;c<3;++c)
|
||||
if(c!=a0 && c!=a1) {
|
||||
a2 = c;
|
||||
break;
|
||||
}
|
||||
assert(a2 != -1);
|
||||
return a2;
|
||||
};
|
||||
|
||||
// must be co-planar
|
||||
Index a2 = opposite_vertex(shared[0].first, shared[1].first);
|
||||
if (! B.supporting_plane().has_on(A.vertex(a2)))
|
||||
return false;
|
||||
|
||||
Index b2 = opposite_vertex(shared[0].second, shared[1].second);
|
||||
|
||||
if (int(CGAL::coplanar_orientation(A.vertex(shared[0].first), A.vertex(shared[1].first), A.vertex(a2))) *
|
||||
int(CGAL::coplanar_orientation(B.vertex(shared[0].second), B.vertex(shared[1].second), B.vertex(b2))) < 0)
|
||||
// There is certainly no self intersection as the non-shared triangle vertices lie on opposite sides of the shared edge.
|
||||
return false;
|
||||
|
||||
// Since A and B are non-degenerate the intersection must be a polygon
|
||||
// (triangle). Either
|
||||
// - the vertex of A (B) opposite the shared edge of lies on B (A), or
|
||||
// - an edge of A intersects and edge of B without sharing a vertex
|
||||
//
|
||||
// Determine if the vertex opposite edge (a0,a1) in triangle A lies in
|
||||
// (intersects) triangle B
|
||||
const auto & opposite_point_inside = [](
|
||||
const Triangle_3 & A, const Index a2, const Triangle_3 & B)
|
||||
-> bool
|
||||
{
|
||||
return CGAL::do_intersect(A.vertex(a2),B);
|
||||
};
|
||||
|
||||
// Determine if edge opposite vertex va in triangle A intersects edge
|
||||
// opposite vertex vb in triangle B.
|
||||
const auto & opposite_edges_intersect = [](
|
||||
const Triangle_3 & A, const Index va,
|
||||
const Triangle_3 & B, const Index vb) -> bool
|
||||
{
|
||||
Segment_3 sa( A.vertex((va+1)%3), A.vertex((va+2)%3));
|
||||
Segment_3 sb( B.vertex((vb+1)%3), B.vertex((vb+2)%3));
|
||||
bool ret = CGAL::do_intersect(sa,sb);
|
||||
return ret;
|
||||
};
|
||||
|
||||
if(
|
||||
!opposite_point_inside(A,a2,B) &&
|
||||
!opposite_point_inside(B,b2,A) &&
|
||||
!opposite_edges_intersect(A,shared[0].first,B,shared[1].second) &&
|
||||
!opposite_edges_intersect(A,shared[1].first,B,shared[0].second))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// there is an intersection indeed
|
||||
count_intersection(fa,fb);
|
||||
if(params.detect_only)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// Construct intersection
|
||||
try
|
||||
{
|
||||
// This can fail for Epick but not Epeck
|
||||
CGAL::Object result = CGAL::intersection(A,B);
|
||||
if(!result.empty())
|
||||
{
|
||||
if(CGAL::object_cast<Segment_3 >(&result))
|
||||
{
|
||||
// not coplanar
|
||||
assert(false &&
|
||||
"Co-planar non-degenerate triangles should intersect over triangle");
|
||||
return false;
|
||||
} else if(CGAL::object_cast<Point_3 >(&result))
|
||||
{
|
||||
// this "shouldn't" happen but does for inexact
|
||||
assert(false &&
|
||||
"Co-planar non-degenerate triangles should intersect over triangle");
|
||||
return false;
|
||||
} else
|
||||
{
|
||||
// Triangle object
|
||||
std::lock_guard<std::mutex> guard(m_offending_lock);
|
||||
offending[fa].push_back({fb, result});
|
||||
offending[fb].push_back({fa, result});
|
||||
return true;
|
||||
}
|
||||
}else
|
||||
{
|
||||
// CGAL::intersection is disagreeing with do_intersect
|
||||
assert(false && "CGAL::intersection should agree with predicate tests");
|
||||
return false;
|
||||
}
|
||||
}catch(...)
|
||||
{
|
||||
// This catches some cgal assertion:
|
||||
// CGAL error: assertion violation!
|
||||
// Expression : is_finite(d)
|
||||
// File : /opt/local/include/CGAL/GMP/Gmpq_type.h
|
||||
// Line : 132
|
||||
// Explanation:
|
||||
// But only if NDEBUG is not defined, otherwise there's an uncaught
|
||||
// "Floating point exception: 8" SIGFPE
|
||||
return false;
|
||||
}
|
||||
// No intersection.
|
||||
return false;
|
||||
}
|
||||
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedIF,
|
||||
typename DerivedJ,
|
||||
typename DerivedIM>
|
||||
inline void igl::copyleft::cgal::SelfIntersectMesh<
|
||||
Kernel,
|
||||
DerivedV,
|
||||
DerivedF,
|
||||
DerivedVV,
|
||||
DerivedFF,
|
||||
DerivedIF,
|
||||
DerivedJ,
|
||||
DerivedIM>::box_intersect(
|
||||
const Box& a,
|
||||
const Box& b)
|
||||
{
|
||||
candidate_triangle_pairs.push_back({a.handle(), b.handle()});
|
||||
}
|
||||
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedIF,
|
||||
typename DerivedJ,
|
||||
typename DerivedIM>
|
||||
inline void igl::copyleft::cgal::SelfIntersectMesh<
|
||||
Kernel,
|
||||
DerivedV,
|
||||
DerivedF,
|
||||
DerivedVV,
|
||||
DerivedFF,
|
||||
DerivedIF,
|
||||
DerivedJ,
|
||||
DerivedIM>::process_intersecting_boxes()
|
||||
{
|
||||
std::mutex exception_mutex;
|
||||
bool exception_fired = false;
|
||||
int exception = -1;
|
||||
// Eventually switching to igl::parallel_for would be good, but currently
|
||||
// igl::parallel_for does not provide a way to catch exceptions fired on a
|
||||
// spawned thread _outside_ of its loop-chunk which is the mechanism used here
|
||||
// to bail out early when `first_only=true` to avoid
|
||||
// O(#candidate_triangle_pairs) behavior.
|
||||
auto process_chunk = [&]( const size_t first, const size_t last) -> void
|
||||
{
|
||||
try
|
||||
{
|
||||
assert(last >= first);
|
||||
|
||||
for (size_t i=first; i<last; i++)
|
||||
{
|
||||
if(exception_fired) return;
|
||||
Index fa=T.size(), fb=T.size();
|
||||
{
|
||||
const auto& tri_pair = candidate_triangle_pairs[i];
|
||||
fa = tri_pair.first - T.begin();
|
||||
fb = tri_pair.second - T.begin();
|
||||
}
|
||||
assert(fa < T.size());
|
||||
assert(fb < T.size());
|
||||
|
||||
if(exception_fired) return;
|
||||
|
||||
const Triangle_3& A = T[fa];
|
||||
const Triangle_3& B = T[fb];
|
||||
|
||||
// Number of combinatorially shared vertices
|
||||
Index comb_shared_vertices = 0;
|
||||
// Number of geometrically shared vertices (*not* including
|
||||
// combinatorially shared)
|
||||
Index geo_shared_vertices = 0;
|
||||
// Keep track of shared vertex indices
|
||||
std::vector<std::pair<Index,Index> > shared;
|
||||
Index ea,eb;
|
||||
for(ea=0;ea<3;ea++)
|
||||
{
|
||||
for(eb=0;eb<3;eb++)
|
||||
{
|
||||
if(F(fa,ea) == F(fb,eb))
|
||||
{
|
||||
comb_shared_vertices++;
|
||||
shared.emplace_back(ea,eb);
|
||||
}else if(A.vertex(ea) == B.vertex(eb))
|
||||
{
|
||||
geo_shared_vertices++;
|
||||
shared.emplace_back(ea,eb);
|
||||
}
|
||||
}
|
||||
}
|
||||
const Index total_shared_vertices =
|
||||
comb_shared_vertices + geo_shared_vertices;
|
||||
if(exception_fired) return;
|
||||
|
||||
if(comb_shared_vertices== 3)
|
||||
{
|
||||
assert(shared.size() == 3);
|
||||
// Combinatorially duplicate face, these should be removed by
|
||||
// preprocessing
|
||||
continue;
|
||||
}
|
||||
if(total_shared_vertices== 3)
|
||||
{
|
||||
assert(shared.size() == 3);
|
||||
// Geometrically duplicate face, these should be removed by
|
||||
// preprocessing
|
||||
continue;
|
||||
}
|
||||
if(total_shared_vertices == 2)
|
||||
{
|
||||
assert(shared.size() == 2);
|
||||
// Q: What about coplanar?
|
||||
//
|
||||
// o o
|
||||
// |\ /|
|
||||
// | \/ |
|
||||
// | /\ |
|
||||
// |/ \|
|
||||
// o----o
|
||||
double_shared_vertex(A,B,fa,fb,shared);
|
||||
continue;
|
||||
}
|
||||
assert(total_shared_vertices<=1);
|
||||
if(total_shared_vertices==1)
|
||||
{
|
||||
single_shared_vertex(A,B,fa,fb,shared[0].first,shared[0].second);
|
||||
}else
|
||||
{
|
||||
intersect(A,B,fa,fb);
|
||||
}
|
||||
}
|
||||
}catch(int e)
|
||||
{
|
||||
std::lock_guard<std::mutex> exception_lock(exception_mutex);
|
||||
exception_fired = true;
|
||||
exception = e;
|
||||
}
|
||||
};
|
||||
const size_t num_threads = default_num_threads();
|
||||
assert(num_threads > 0);
|
||||
const size_t num_pairs = candidate_triangle_pairs.size();
|
||||
const size_t chunk_size = num_pairs / num_threads;
|
||||
std::vector<std::thread> threads;
|
||||
for (size_t i=0; i<num_threads-1; i++)
|
||||
{
|
||||
threads.emplace_back(process_chunk, i*chunk_size, (i+1)*chunk_size);
|
||||
}
|
||||
// Do some work in the master thread.
|
||||
process_chunk((num_threads-1)*chunk_size, num_pairs);
|
||||
for (auto& t : threads)
|
||||
{
|
||||
if (t.joinable()) t.join();
|
||||
}
|
||||
if(exception_fired) throw exception;
|
||||
//process_chunk(0, candidate_triangle_pairs.size());
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,88 +0,0 @@
|
||||
// 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 "assign.h"
|
||||
#include "../../parallel_for.h"
|
||||
#include "assign_scalar.h"
|
||||
|
||||
template <typename DerivedC, typename DerivedD>
|
||||
IGL_INLINE void igl::copyleft::cgal::assign(
|
||||
const Eigen::MatrixBase<DerivedC> & C,
|
||||
const bool slow_and_more_precise,
|
||||
Eigen::PlainObjectBase<DerivedD> & D)
|
||||
{
|
||||
D.resizeLike(C);
|
||||
igl::parallel_for(C.size(),[&](Eigen::Index k)
|
||||
{
|
||||
const Eigen::Index i = k%C.rows();
|
||||
const Eigen::Index j = k/C.rows();
|
||||
assign_scalar(C(i,j),slow_and_more_precise,D(i,j));
|
||||
},1000);
|
||||
}
|
||||
template <typename DerivedC, typename DerivedD>
|
||||
IGL_INLINE void igl::copyleft::cgal::assign(
|
||||
const Eigen::MatrixBase<DerivedC> & C,
|
||||
Eigen::PlainObjectBase<DerivedD> & D)
|
||||
{
|
||||
const bool slow_and_more_precise = false;
|
||||
return assign(C,slow_and_more_precise,D);
|
||||
}
|
||||
|
||||
template <typename ReturnScalar, typename DerivedC>
|
||||
IGL_INLINE
|
||||
Eigen::Matrix<
|
||||
ReturnScalar,
|
||||
DerivedC::RowsAtCompileTime,
|
||||
DerivedC::ColsAtCompileTime,
|
||||
1,
|
||||
DerivedC::MaxRowsAtCompileTime,
|
||||
DerivedC::MaxColsAtCompileTime>
|
||||
igl::copyleft::cgal::assign(
|
||||
const Eigen::MatrixBase<DerivedC> & C)
|
||||
{
|
||||
Eigen::Matrix<
|
||||
ReturnScalar,
|
||||
DerivedC::RowsAtCompileTime,
|
||||
DerivedC::ColsAtCompileTime,
|
||||
1,
|
||||
DerivedC::MaxRowsAtCompileTime,
|
||||
DerivedC::MaxColsAtCompileTime> D;
|
||||
assign(C,D);
|
||||
return D;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Epeck::FT, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -1, -1>, Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -1, -1>, Eigen::Matrix<CGAL::Epeck::FT, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -1, -1>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Epeck::FT, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Epeck::FT, -1, 3, 0, -1, 3>, Eigen::Matrix<CGAL::Epeck::FT, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Epeck::FT, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Epeck::FT, 1, -1, 1, 1, -1>, Eigen::Matrix<double, 1, -1, 1, 1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, 1, -1, 1, 1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Epeck::FT, 8, 3, 0, 8, 3>, Eigen::Matrix<CGAL::Epeck::FT, 8, 3, 0, 8, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, 8, 3, 0, 8, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, 8, 3, 0, 8, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Epeck::FT, 8, 3, 0, 8, 3>, Eigen::Matrix<double, 8, 3, 0, 8, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, 8, 3, 0, 8, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 8, 3, 0, 8, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Epeck::FT, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<CGAL::Epeck::FT, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<double, 1, -1, 1, 1, -1>, Eigen::Matrix<CGAL::Epeck::FT, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, 1, 3, 1, 1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<CGAL::Epeck::FT, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -1, -1> >&);
|
||||
#endif
|
||||
@@ -1,56 +0,0 @@
|
||||
// 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/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_ASSIGN_H
|
||||
#define IGL_COPYLEFT_CGAL_ASSIGN_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
/// Vector version of assign_scalar
|
||||
///
|
||||
/// @param[in] C matrix of scalars
|
||||
/// @param[in] slow_and_more_precise see assign_scalar
|
||||
/// @param[out] D matrix same size as C
|
||||
///
|
||||
/// \see assign_scalar
|
||||
template <typename DerivedC, typename DerivedD>
|
||||
IGL_INLINE void assign(
|
||||
const Eigen::MatrixBase<DerivedC> & C,
|
||||
const bool slow_and_more_precise,
|
||||
Eigen::PlainObjectBase<DerivedD> & D);
|
||||
/// \overload
|
||||
template <typename DerivedC, typename DerivedD>
|
||||
IGL_INLINE void assign(
|
||||
const Eigen::MatrixBase<DerivedC> & C,
|
||||
Eigen::PlainObjectBase<DerivedD> & D);
|
||||
/// \overload
|
||||
template <typename ReturnScalar, typename DerivedC>
|
||||
IGL_INLINE
|
||||
Eigen::Matrix<
|
||||
ReturnScalar,
|
||||
DerivedC::RowsAtCompileTime,
|
||||
DerivedC::ColsAtCompileTime,
|
||||
1,
|
||||
DerivedC::MaxRowsAtCompileTime,
|
||||
DerivedC::MaxColsAtCompileTime>
|
||||
assign(
|
||||
const Eigen::MatrixBase<DerivedC> & C);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "assign.cpp"
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,199 +0,0 @@
|
||||
// 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 "assign_scalar.h"
|
||||
|
||||
template <>
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const CGAL::Epeck::FT & rhs,
|
||||
const bool & slow_and_more_precise,
|
||||
double & lhs)
|
||||
{
|
||||
if(slow_and_more_precise)
|
||||
{
|
||||
return assign_scalar(rhs,lhs);
|
||||
}else
|
||||
{
|
||||
// While this is significantly faster (100x), this does not guarantee that
|
||||
// two equivalent rationals produce the same double (e.g.,
|
||||
// CGAL::to_double(⅓) ≠ CGAL::to_double(1-⅔))
|
||||
// https://github.com/CGAL/cgal/discussions/6000 For remesh_intersections,
|
||||
// `unique` is called _after_ rounding to floats, avoiding more expensive
|
||||
// rational equality tests. To operate correctly, we need that a=b ⇒
|
||||
// double(a)=double(b). Alternatively, we could require that
|
||||
// remesh_intersections conduct its `unique` operation on rationals. This is
|
||||
// even more expensive (4x) and most of the time probably overkill, though
|
||||
// it is argueably more correct in terms of producing the correct topology
|
||||
// (despite degeneracies that appear during rounding). On the other hand,
|
||||
// this rounding-before-unique only occurs if the requested output is float,
|
||||
// so its a question of combinatorial vs geometric degeneracies. Argueably,
|
||||
// combinatorial degeneracies are more reliably detected.
|
||||
//
|
||||
//lhs = CGAL::to_double(rhs);
|
||||
lhs = CGAL::to_double(rhs.exact());
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const CGAL::Epeck::FT & rhs,
|
||||
const bool & slow_and_more_precise,
|
||||
float & lhs)
|
||||
{
|
||||
double d;
|
||||
igl::copyleft::cgal::assign_scalar(rhs,slow_and_more_precise,d);
|
||||
lhs = float(d);
|
||||
}
|
||||
|
||||
// If we haven't specialized the types then `slow_and_more_precise` doesn't make sense.
|
||||
template <typename RHS, typename LHS>
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const RHS & rhs,
|
||||
const bool & slow_and_more_precise,
|
||||
LHS & lhs)
|
||||
{
|
||||
return assign_scalar(rhs,lhs);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const CGAL::Epeck::FT & cgal,
|
||||
CGAL::Epeck::FT & d)
|
||||
{
|
||||
d = cgal;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const CGAL::Epeck::FT & _cgal,
|
||||
double & d)
|
||||
{
|
||||
// FORCE evaluation of the exact type otherwise interval might be huge.
|
||||
const CGAL::Epeck::FT cgal = _cgal.exact();
|
||||
const auto interval = CGAL::to_interval(cgal);
|
||||
d = interval.first;
|
||||
do {
|
||||
const double next = nextafter(d, interval.second);
|
||||
if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break;
|
||||
d = next;
|
||||
} while (d < interval.second);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const CGAL::Epeck::FT & _cgal,
|
||||
float& d)
|
||||
{
|
||||
// FORCE evaluation of the exact type otherwise interval might be huge.
|
||||
const CGAL::Epeck::FT cgal = _cgal.exact();
|
||||
const auto interval = CGAL::to_interval(cgal);
|
||||
d = interval.first;
|
||||
do {
|
||||
const float next = nextafter(d, float(interval.second));
|
||||
if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break;
|
||||
d = next;
|
||||
} while (d < float(interval.second));
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const double & c,
|
||||
double & d)
|
||||
{
|
||||
d = c;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const float& c,
|
||||
float& d)
|
||||
{
|
||||
d = c;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const float& c,
|
||||
double& d)
|
||||
{
|
||||
d = c;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
|
||||
CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & d)
|
||||
{
|
||||
d = cgal;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
|
||||
double & d)
|
||||
{
|
||||
const auto interval = CGAL::to_interval(cgal);
|
||||
d = interval.first;
|
||||
do {
|
||||
const double next = nextafter(d, interval.second);
|
||||
if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break;
|
||||
d = next;
|
||||
} while (d < interval.second);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
|
||||
float& d)
|
||||
{
|
||||
const auto interval = CGAL::to_interval(cgal);
|
||||
d = interval.first;
|
||||
do {
|
||||
const float next = nextafter(d, float(interval.second));
|
||||
if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break;
|
||||
d = next;
|
||||
} while (d < float(interval.second));
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
|
||||
CGAL::Simple_cartesian<mpq_class>::FT & d)
|
||||
{
|
||||
d = cgal;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
|
||||
double & d)
|
||||
{
|
||||
const auto interval = CGAL::to_interval(cgal);
|
||||
d = interval.first;
|
||||
do {
|
||||
const double next = nextafter(d, interval.second);
|
||||
if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break;
|
||||
d = next;
|
||||
} while (d < interval.second);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
|
||||
float& d)
|
||||
{
|
||||
const auto interval = CGAL::to_interval(cgal);
|
||||
d = interval.first;
|
||||
do {
|
||||
const float next = nextafter(d, float(interval.second));
|
||||
if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break;
|
||||
d = next;
|
||||
} while (d < float(interval.second));
|
||||
}
|
||||
|
||||
#endif // WIN32
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::assign_scalar<float, double>(float const&, bool const&, double&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::assign_scalar<float, CGAL::Epeck::FT >(float const&, bool const&, CGAL::Epeck::FT&);
|
||||
template void igl::copyleft::cgal::assign_scalar<double, double>(double const&, bool const&, double&);
|
||||
template void igl::copyleft::cgal::assign_scalar<double, CGAL::Epeck::FT >(double const&, bool const&, CGAL::Epeck::FT&);
|
||||
template void igl::copyleft::cgal::assign_scalar<CGAL::Epeck::FT, CGAL::Epeck::FT >(CGAL::Epeck::FT const&, bool const&, CGAL::Epeck::FT&);
|
||||
#endif
|
||||
@@ -1,109 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
// Copyright (C) 2021 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_COPYLEFT_CGAL_ASSIGN_SCALAR_H
|
||||
#define IGL_COPYLEFT_CGAL_ASSIGN_SCALAR_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel_with_sqrt.h>
|
||||
#ifndef WIN32
|
||||
#include <CGAL/gmpxx.h>
|
||||
#endif
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
/// Conduct the casting copy:
|
||||
/// lhs = rhs
|
||||
/// using `slow_and_more_precise` rounding if more desired.
|
||||
///
|
||||
/// @tparam RHS right-hand side scalar type
|
||||
/// @tparam LHS left-hand side scalar type
|
||||
/// @param[in] rhs right-hand side scalar
|
||||
/// @param[in] slow_and_more_precise when appropriate use more elaborate rounding
|
||||
/// guaranteed to find a closest lhs value in an absolute value sense.
|
||||
/// Think of `slow_and_more_precise=true` as "round to closest number"
|
||||
/// and `slow_and_more_precise=false` as "round down/up". CGAL's number
|
||||
/// types are bit mysterious about how exactly rounding is conducted.
|
||||
/// For example, the rationals created during remesh_intersections on
|
||||
/// floating point input appear to be tightly rounded up or down so the
|
||||
/// difference with the `slow_and_more_precise=true` will be exactly
|
||||
/// zero 50% of the time and "one floating point unit" (at whatever
|
||||
/// scale) the other 50% of the time.
|
||||
/// @param[out] lhs left-hand side scalar
|
||||
template <typename RHS, typename LHS>
|
||||
IGL_INLINE void assign_scalar(
|
||||
const RHS & rhs,
|
||||
const bool & slow_and_more_precise,
|
||||
LHS & lhs);
|
||||
/// \overload
|
||||
/// \brief For legacy reasons, all of these overload uses
|
||||
/// `slow_and_more_precise=true`. This is subject to change if we determine
|
||||
/// it is sufficiently overkill. In that case, we'd create a new
|
||||
/// non-overloaded function.
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Epeck::FT & cgal,
|
||||
CGAL::Epeck::FT & d);
|
||||
/// \overload
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Epeck::FT & cgal,
|
||||
double & d);
|
||||
/// \overload
|
||||
IGL_INLINE void assign_scalar(
|
||||
/// \overload
|
||||
const CGAL::Epeck::FT & cgal,
|
||||
float& d);
|
||||
IGL_INLINE void assign_scalar(
|
||||
/// \overload
|
||||
const double & c,
|
||||
double & d);
|
||||
/// \overload
|
||||
IGL_INLINE void assign_scalar(
|
||||
const float& c,
|
||||
float & d);
|
||||
/// \overload
|
||||
IGL_INLINE void assign_scalar(
|
||||
const float& c,
|
||||
double& d);
|
||||
/// \overload
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
|
||||
CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & d);
|
||||
/// \overload
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
|
||||
double & d);
|
||||
/// \overload
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
|
||||
float& d);
|
||||
#ifndef WIN32
|
||||
/// \overload
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
|
||||
CGAL::Simple_cartesian<mpq_class>::FT & d);
|
||||
/// \overload
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
|
||||
double & d);
|
||||
/// \overload
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
|
||||
float& d);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "assign_scalar.cpp"
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,16 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2017 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 "../../barycenter.h"
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
#undef IGL_STATIC_LIBRARY
|
||||
#include "../../barycenter.cpp"
|
||||
// Explicit template instantiation
|
||||
template void igl::barycenter<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -1,36 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Qingnan Zhou <qnzhou@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 "cell_adjacency.h"
|
||||
|
||||
template <typename DerivedC>
|
||||
IGL_INLINE void igl::copyleft::cgal::cell_adjacency(
|
||||
const Eigen::PlainObjectBase<DerivedC>& per_patch_cells,
|
||||
const size_t num_cells,
|
||||
std::vector<std::set<std::tuple<typename DerivedC::Scalar, bool, size_t> > >&
|
||||
adjacency_list) {
|
||||
|
||||
const size_t num_patches = per_patch_cells.rows();
|
||||
adjacency_list.resize(num_cells);
|
||||
for (size_t i=0; i<num_patches; i++) {
|
||||
const int positive_cell = per_patch_cells(i,0);
|
||||
const int negative_cell = per_patch_cells(i,1);
|
||||
adjacency_list[positive_cell].emplace(negative_cell, false, i);
|
||||
adjacency_list[negative_cell].emplace(positive_cell, true, i);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::cell_adjacency<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, unsigned long, std::vector<std::set<std::tuple<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, bool, unsigned long>, std::less<std::tuple<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, bool, unsigned long> >, std::allocator<std::tuple<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, bool, unsigned long> > >, std::allocator<std::set<std::tuple<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, bool, unsigned long>, std::less<std::tuple<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, bool, unsigned long> >, std::allocator<std::tuple<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, bool, unsigned long> > > > >&);
|
||||
#ifdef WIN32
|
||||
template void igl::copyleft::cgal::cell_adjacency<class Eigen::Matrix<int, -1, -1, 0, -1, -1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, unsigned __int64, class std::vector<class std::set<class std::tuple<int, bool, unsigned __int64>, struct std::less<class std::tuple<int, bool, unsigned __int64>>, class std::allocator<class std::tuple<int, bool, unsigned __int64>>>, class std::allocator<class std::set<class std::tuple<int, bool, unsigned __int64>, struct std::less<class std::tuple<int, bool, unsigned __int64>>, class std::allocator<class std::tuple<int, bool, unsigned __int64>>>>> &);
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,46 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Qingnan Zhou <qnzhou@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_COPYLEFT_CGAL_CELL_ADJACENCY_H
|
||||
#define IGL_COPYLEFT_CGAL_CELL_ADJACENCY_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <set>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
/// Determine adjacency of cells
|
||||
///
|
||||
/// @param[in] per_patch_cells #P by 2 list of cell labels on each side
|
||||
/// of each patch. Cell labels are assumed to be continuous from 0 to #C.
|
||||
/// @param[in] num_cells number of cells.
|
||||
/// @param[out] adjacency_list #C array of list of adjcent cell
|
||||
/// information. If cell i and cell j are adjacent via patch x, where i
|
||||
/// is on the positive side of x, and j is on the negative side. Then,
|
||||
/// adjacency_list[i] will contain the entry {j, false, x} and
|
||||
/// adjacency_list[j] will contain the entry {i, true, x}
|
||||
template < typename DerivedC >
|
||||
IGL_INLINE void cell_adjacency(
|
||||
const Eigen::PlainObjectBase<DerivedC>& per_patch_cells,
|
||||
const size_t num_cells,
|
||||
std::vector<std::set<std::tuple<typename DerivedC::Scalar, bool, size_t> > >&
|
||||
adjacency_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "cell_adjacency.cpp"
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,509 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@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 "closest_facet.h"
|
||||
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "order_facets_around_edge.h"
|
||||
#include "submesh_aabb_tree.h"
|
||||
#include "../../vertex_triangle_adjacency.h"
|
||||
#include "../../LinSpaced.h"
|
||||
//#include "../../writePLY.h"
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename DerivedP,
|
||||
typename DerivedEMAP,
|
||||
typename DeriveduEC,
|
||||
typename DeriveduEE,
|
||||
typename Kernel,
|
||||
typename DerivedR,
|
||||
typename DerivedS >
|
||||
IGL_INLINE void igl::copyleft::cgal::closest_facet(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
const Eigen::PlainObjectBase<DeriveduEC>& uEC,
|
||||
const Eigen::PlainObjectBase<DeriveduEE>& uEE,
|
||||
const std::vector<std::vector<size_t> > & VF,
|
||||
const std::vector<std::vector<size_t> > & VFi,
|
||||
const CGAL::AABB_tree<
|
||||
CGAL::AABB_traits<
|
||||
Kernel,
|
||||
CGAL::AABB_triangle_primitive<
|
||||
Kernel, typename std::vector<
|
||||
typename Kernel::Triangle_3 >::iterator > > > & tree,
|
||||
const std::vector<typename Kernel::Triangle_3 > & triangles,
|
||||
const std::vector<bool> & in_I,
|
||||
Eigen::PlainObjectBase<DerivedR>& R,
|
||||
Eigen::PlainObjectBase<DerivedS>& S)
|
||||
{
|
||||
typedef typename Kernel::Point_3 Point_3;
|
||||
typedef typename Kernel::Plane_3 Plane_3;
|
||||
typedef typename Kernel::Segment_3 Segment_3;
|
||||
typedef typename Kernel::Triangle_3 Triangle;
|
||||
typedef typename std::vector<Triangle>::iterator Iterator;
|
||||
typedef typename CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
|
||||
typedef typename CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
|
||||
typedef typename CGAL::AABB_tree<AABB_triangle_traits> Tree;
|
||||
|
||||
const size_t num_faces = I.rows();
|
||||
if (F.rows() <= 0 || I.rows() <= 0) {
|
||||
throw std::runtime_error(
|
||||
"Closest facet cannot be computed on empty mesh.");
|
||||
}
|
||||
|
||||
auto on_the_positive_side = [&](size_t fid, const Point_3& p) -> bool
|
||||
{
|
||||
const auto& f = F.row(fid).eval();
|
||||
Point_3 v0(V(f[0], 0), V(f[0], 1), V(f[0], 2));
|
||||
Point_3 v1(V(f[1], 0), V(f[1], 1), V(f[1], 2));
|
||||
Point_3 v2(V(f[2], 0), V(f[2], 1), V(f[2], 2));
|
||||
auto ori = CGAL::orientation(v0, v1, v2, p);
|
||||
switch (ori) {
|
||||
case CGAL::POSITIVE:
|
||||
return true;
|
||||
case CGAL::NEGATIVE:
|
||||
return false;
|
||||
case CGAL::COPLANAR:
|
||||
// Warning:
|
||||
// This can only happen if fid contains a boundary edge.
|
||||
// Categorized this ambiguous case as negative side.
|
||||
return false;
|
||||
default:
|
||||
throw std::runtime_error("Unknown CGAL state.");
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
auto get_orientation = [&](size_t fid, size_t s, size_t d) -> bool
|
||||
{
|
||||
const auto& f = F.row(fid);
|
||||
if ((size_t)f[0] == s && (size_t)f[1] == d) return false;
|
||||
else if ((size_t)f[1] == s && (size_t)f[2] == d) return false;
|
||||
else if ((size_t)f[2] == s && (size_t)f[0] == d) return false;
|
||||
else if ((size_t)f[0] == d && (size_t)f[1] == s) return true;
|
||||
else if ((size_t)f[1] == d && (size_t)f[2] == s) return true;
|
||||
else if ((size_t)f[2] == d && (size_t)f[0] == s) return true;
|
||||
else {
|
||||
throw std::runtime_error(
|
||||
"Cannot compute orientation due to incorrect connectivity");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
auto index_to_signed_index = [&](size_t index, bool ori) -> int{
|
||||
return (index+1) * (ori? 1:-1);
|
||||
};
|
||||
//auto signed_index_to_index = [&](int signed_index) -> size_t {
|
||||
// return abs(signed_index) - 1;
|
||||
//};
|
||||
|
||||
enum ElementType { VERTEX, EDGE, FACE };
|
||||
auto determine_element_type = [&](const Point_3& p, const size_t fid,
|
||||
size_t& element_index) -> ElementType {
|
||||
const auto& tri = triangles[fid];
|
||||
const Point_3 p0 = tri[0];
|
||||
const Point_3 p1 = tri[1];
|
||||
const Point_3 p2 = tri[2];
|
||||
|
||||
if (p == p0) { element_index = 0; return VERTEX; }
|
||||
if (p == p1) { element_index = 1; return VERTEX; }
|
||||
if (p == p2) { element_index = 2; return VERTEX; }
|
||||
if (CGAL::collinear(p0, p1, p)) { element_index = 2; return EDGE; }
|
||||
if (CGAL::collinear(p1, p2, p)) { element_index = 0; return EDGE; }
|
||||
if (CGAL::collinear(p2, p0, p)) { element_index = 1; return EDGE; }
|
||||
|
||||
element_index = 0;
|
||||
return FACE;
|
||||
};
|
||||
|
||||
auto process_edge_case = [&](
|
||||
size_t query_idx,
|
||||
const size_t s, const size_t d,
|
||||
size_t preferred_facet,
|
||||
bool& orientation) -> size_t
|
||||
{
|
||||
Point_3 query_point(
|
||||
P(query_idx, 0),
|
||||
P(query_idx, 1),
|
||||
P(query_idx, 2));
|
||||
|
||||
size_t corner_idx = std::numeric_limits<size_t>::max();
|
||||
if ((s == F(preferred_facet, 0) && d == F(preferred_facet, 1)) ||
|
||||
(s == F(preferred_facet, 1) && d == F(preferred_facet, 0)))
|
||||
{
|
||||
corner_idx = 2;
|
||||
} else if ((s == F(preferred_facet, 0) && d == F(preferred_facet, 2)) ||
|
||||
(s == F(preferred_facet, 2) && d == F(preferred_facet, 0)))
|
||||
{
|
||||
corner_idx = 1;
|
||||
} else if ((s == F(preferred_facet, 1) && d == F(preferred_facet, 2)) ||
|
||||
(s == F(preferred_facet, 2) && d == F(preferred_facet, 1)))
|
||||
{
|
||||
corner_idx = 0;
|
||||
} else
|
||||
{
|
||||
std::cerr << "s: " << s << "\t d:" << d << std::endl;
|
||||
std::cerr << F.row(preferred_facet) << std::endl;
|
||||
throw std::runtime_error(
|
||||
"Invalid connectivity, edge does not belong to facet");
|
||||
}
|
||||
|
||||
auto ueid = EMAP(preferred_facet + corner_idx * F.rows());
|
||||
std::vector<size_t> intersected_face_indices;
|
||||
//auto eids = uE2E[ueid];
|
||||
//for (auto eid : eids)
|
||||
for(size_t j = uEC(ueid);j<uEC(ueid+1);j++)
|
||||
{
|
||||
const size_t eid = uEE(j);
|
||||
const size_t fid = eid % F.rows();
|
||||
if (in_I[fid])
|
||||
{
|
||||
intersected_face_indices.push_back(fid);
|
||||
}
|
||||
}
|
||||
|
||||
const size_t num_intersected_faces = intersected_face_indices.size();
|
||||
std::vector<int> intersected_face_signed_indices(num_intersected_faces);
|
||||
std::transform(
|
||||
intersected_face_indices.begin(),
|
||||
intersected_face_indices.end(),
|
||||
intersected_face_signed_indices.begin(),
|
||||
[&](size_t index) {
|
||||
return index_to_signed_index(
|
||||
index, get_orientation(index, s,d));
|
||||
});
|
||||
|
||||
assert(num_intersected_faces >= 1);
|
||||
if (num_intersected_faces == 1)
|
||||
{
|
||||
// The edge must be a boundary edge. Thus, the orientation can be
|
||||
// simply determined by checking if the query point is on the
|
||||
// positive side of the facet.
|
||||
const size_t fid = intersected_face_indices[0];
|
||||
orientation = on_the_positive_side(fid, query_point);
|
||||
return fid;
|
||||
}
|
||||
|
||||
Eigen::VectorXi order;
|
||||
DerivedP pivot = P.row(query_idx).eval();
|
||||
igl::copyleft::cgal::order_facets_around_edge(V, F, s, d,
|
||||
intersected_face_signed_indices,
|
||||
pivot, order);
|
||||
|
||||
// Although first and last are equivalent, make the choice based on
|
||||
// preferred_facet.
|
||||
const size_t first = order[0];
|
||||
const size_t last = order[num_intersected_faces-1];
|
||||
if (intersected_face_indices[first] == preferred_facet) {
|
||||
orientation = intersected_face_signed_indices[first] < 0;
|
||||
return intersected_face_indices[first];
|
||||
} else if (intersected_face_indices[last] == preferred_facet) {
|
||||
orientation = intersected_face_signed_indices[last] > 0;
|
||||
return intersected_face_indices[last];
|
||||
} else {
|
||||
orientation = intersected_face_signed_indices[order[0]] < 0;
|
||||
return intersected_face_indices[order[0]];
|
||||
}
|
||||
};
|
||||
|
||||
auto process_face_case = [&](
|
||||
const size_t query_idx, const Point_3& closest_point,
|
||||
const size_t fid, bool& orientation) -> size_t {
|
||||
const auto& f = F.row(I(fid, 0));
|
||||
return process_edge_case(query_idx, f[0], f[1], I(fid, 0), orientation);
|
||||
};
|
||||
|
||||
// Given that the closest point to query point P(query_idx,:) on (V,F(I,:))
|
||||
// is the vertex at V(s,:) which is incident at least on triangle
|
||||
// F(preferred_facet,:), determine a facet incident on V(s,:) that is
|
||||
// _exposed_ to the query point and determine whether that facet is facing
|
||||
// _toward_ or _away_ from the query point.
|
||||
//
|
||||
// Inputs:
|
||||
// query_idx index into P of query point
|
||||
// s index into V of closest point at vertex
|
||||
// preferred_facet facet incident on s
|
||||
// Outputs:
|
||||
// orientation whether returned face is facing toward or away from
|
||||
// query (parity unclear)
|
||||
// Returns face guaranteed to be "exposed" to P(query_idx,:)
|
||||
auto process_vertex_case = [&](
|
||||
const size_t query_idx,
|
||||
size_t s,
|
||||
size_t preferred_facet,
|
||||
bool& orientation) -> size_t
|
||||
{
|
||||
const Point_3 query_point(
|
||||
P(query_idx, 0), P(query_idx, 1), P(query_idx, 2));
|
||||
const Point_3 closest_point(V(s, 0), V(s, 1), V(s, 2));
|
||||
std::vector<size_t> adj_faces;
|
||||
std::vector<size_t> adj_face_corners;
|
||||
{
|
||||
// Gather adj faces to s within I.
|
||||
const auto& all_adj_faces = VF[s];
|
||||
const auto& all_adj_face_corners = VFi[s];
|
||||
const size_t num_all_adj_faces = all_adj_faces.size();
|
||||
for (size_t i=0; i<num_all_adj_faces; i++)
|
||||
{
|
||||
const size_t fid = all_adj_faces[i];
|
||||
// Shouldn't this always be true if I is a full connected component?
|
||||
if (in_I[fid])
|
||||
{
|
||||
adj_faces.push_back(fid);
|
||||
adj_face_corners.push_back(all_adj_face_corners[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
const size_t num_adj_faces = adj_faces.size();
|
||||
assert(num_adj_faces > 0);
|
||||
|
||||
std::set<size_t> adj_vertices_set;
|
||||
std::unordered_multimap<size_t, size_t> v2f;
|
||||
for (size_t i=0; i<num_adj_faces; i++)
|
||||
{
|
||||
const size_t fid = adj_faces[i];
|
||||
const size_t cid = adj_face_corners[i];
|
||||
const auto& f = F.row(adj_faces[i]);
|
||||
const size_t next = f[(cid+1)%3];
|
||||
const size_t prev = f[(cid+2)%3];
|
||||
adj_vertices_set.insert(next);
|
||||
adj_vertices_set.insert(prev);
|
||||
v2f.insert({{next, fid}, {prev, fid}});
|
||||
}
|
||||
const size_t num_adj_vertices = adj_vertices_set.size();
|
||||
std::vector<size_t> adj_vertices(num_adj_vertices);
|
||||
std::copy(adj_vertices_set.begin(), adj_vertices_set.end(),
|
||||
adj_vertices.begin());
|
||||
|
||||
std::vector<Point_3> adj_points;
|
||||
for (size_t vid : adj_vertices)
|
||||
{
|
||||
adj_points.emplace_back(V(vid,0), V(vid,1), V(vid,2));
|
||||
}
|
||||
|
||||
// A plane is on the exterior if all adj_points lies on or to
|
||||
// one side of the plane.
|
||||
auto is_on_exterior = [&](const Plane_3& separator) -> bool{
|
||||
size_t positive=0;
|
||||
size_t negative=0;
|
||||
size_t coplanar=0;
|
||||
for (const auto& point : adj_points) {
|
||||
switch(separator.oriented_side(point)) {
|
||||
case CGAL::ON_POSITIVE_SIDE:
|
||||
positive++;
|
||||
break;
|
||||
case CGAL::ON_NEGATIVE_SIDE:
|
||||
negative++;
|
||||
break;
|
||||
case CGAL::ON_ORIENTED_BOUNDARY:
|
||||
coplanar++;
|
||||
break;
|
||||
default:
|
||||
throw "Unknown plane-point orientation";
|
||||
}
|
||||
}
|
||||
auto query_orientation = separator.oriented_side(query_point);
|
||||
if (query_orientation == CGAL::ON_ORIENTED_BOUNDARY &&
|
||||
(positive == 0 && negative == 0)) {
|
||||
// All adj vertices and query point are coplanar.
|
||||
// In this case, all separators are equally valid.
|
||||
return true;
|
||||
} else {
|
||||
bool r = (positive == 0 && query_orientation == CGAL::POSITIVE)
|
||||
|| (negative == 0 && query_orientation == CGAL::NEGATIVE);
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
size_t d = std::numeric_limits<size_t>::max();
|
||||
for (size_t i=0; i<num_adj_vertices; i++) {
|
||||
const size_t vi = adj_vertices[i];
|
||||
for (size_t j=i+1; j<num_adj_vertices; j++) {
|
||||
Plane_3 separator(closest_point, adj_points[i], adj_points[j]);
|
||||
if (separator.is_degenerate()) {
|
||||
continue;
|
||||
}
|
||||
if (is_on_exterior(separator)) {
|
||||
if (!CGAL::collinear(
|
||||
query_point, adj_points[i], closest_point)) {
|
||||
d = vi;
|
||||
break;
|
||||
} else {
|
||||
d = adj_vertices[j];
|
||||
assert(!CGAL::collinear(
|
||||
query_point, adj_points[j], closest_point));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (d == std::numeric_limits<size_t>::max()) {
|
||||
Eigen::MatrixXd tmp_vertices(V.rows(), V.cols());
|
||||
for (size_t i=0; i<V.rows(); i++) {
|
||||
for (size_t j=0; j<V.cols(); j++) {
|
||||
tmp_vertices(i,j) = CGAL::to_double(V(i,j));
|
||||
}
|
||||
}
|
||||
Eigen::MatrixXi tmp_faces(adj_faces.size(), 3);
|
||||
for (size_t i=0; i<adj_faces.size(); i++) {
|
||||
tmp_faces.row(i) = F.row(adj_faces[i]);
|
||||
}
|
||||
//igl::writePLY("debug.ply", tmp_vertices, tmp_faces, false);
|
||||
throw std::runtime_error("Invalid vertex neighborhood");
|
||||
}
|
||||
const auto itr = v2f.equal_range(d);
|
||||
assert(itr.first != itr.second);
|
||||
|
||||
return process_edge_case(query_idx, s, d, itr.first->second, orientation);
|
||||
};
|
||||
|
||||
const size_t num_queries = P.rows();
|
||||
R.resize(num_queries, 1);
|
||||
S.resize(num_queries, 1);
|
||||
for (size_t i=0; i<num_queries; i++) {
|
||||
const Point_3 query(P(i,0), P(i,1), P(i,2));
|
||||
auto projection = tree.closest_point_and_primitive(query);
|
||||
const Point_3 closest_point = projection.first;
|
||||
size_t fid = projection.second - triangles.begin();
|
||||
bool fid_ori = false;
|
||||
|
||||
// Gether all facets sharing the closest point.
|
||||
typename std::vector<typename Tree::Primitive_id> intersected_faces;
|
||||
tree.all_intersected_primitives(Segment_3(closest_point, query),
|
||||
std::back_inserter(intersected_faces));
|
||||
const size_t num_intersected_faces = intersected_faces.size();
|
||||
std::vector<size_t> intersected_face_indices(num_intersected_faces);
|
||||
std::transform(intersected_faces.begin(),
|
||||
intersected_faces.end(),
|
||||
intersected_face_indices.begin(),
|
||||
[&](const typename Tree::Primitive_id& itr) -> size_t
|
||||
{ return I(itr-triangles.begin(), 0); });
|
||||
|
||||
size_t element_index;
|
||||
auto element_type = determine_element_type(closest_point, fid,
|
||||
element_index);
|
||||
switch(element_type) {
|
||||
case VERTEX:
|
||||
{
|
||||
const auto& f = F.row(I(fid, 0));
|
||||
const size_t s = f[element_index];
|
||||
fid = process_vertex_case(i, s, I(fid, 0), fid_ori);
|
||||
}
|
||||
break;
|
||||
case EDGE:
|
||||
{
|
||||
const auto& f = F.row(I(fid, 0));
|
||||
const size_t s = f[(element_index+1)%3];
|
||||
const size_t d = f[(element_index+2)%3];
|
||||
fid = process_edge_case(i, s, d, I(fid, 0), fid_ori);
|
||||
}
|
||||
break;
|
||||
case FACE:
|
||||
{
|
||||
fid = process_face_case(i, closest_point, fid, fid_ori);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unknown element type.");
|
||||
}
|
||||
|
||||
|
||||
R(i,0) = fid;
|
||||
S(i,0) = fid_ori;
|
||||
}
|
||||
}
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename DerivedP,
|
||||
typename DerivedEMAP,
|
||||
typename DeriveduEC,
|
||||
typename DeriveduEE,
|
||||
typename DerivedR,
|
||||
typename DerivedS >
|
||||
IGL_INLINE void igl::copyleft::cgal::closest_facet(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
const Eigen::PlainObjectBase<DeriveduEC>& uEC,
|
||||
const Eigen::PlainObjectBase<DeriveduEE>& uEE,
|
||||
Eigen::PlainObjectBase<DerivedR>& R,
|
||||
Eigen::PlainObjectBase<DerivedS>& S)
|
||||
{
|
||||
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
|
||||
typedef Kernel::Point_3 Point_3;
|
||||
typedef Kernel::Plane_3 Plane_3;
|
||||
typedef Kernel::Segment_3 Segment_3;
|
||||
typedef Kernel::Triangle_3 Triangle;
|
||||
typedef std::vector<Triangle>::iterator Iterator;
|
||||
typedef CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
|
||||
typedef CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
|
||||
typedef CGAL::AABB_tree<AABB_triangle_traits> Tree;
|
||||
|
||||
if (F.rows() <= 0 || I.rows() <= 0) {
|
||||
throw std::runtime_error(
|
||||
"Closest facet cannot be computed on empty mesh.");
|
||||
}
|
||||
|
||||
std::vector<std::vector<size_t> > VF, VFi;
|
||||
igl::vertex_triangle_adjacency(V.rows(), F, VF, VFi);
|
||||
std::vector<bool> in_I;
|
||||
std::vector<Triangle> triangles;
|
||||
Tree tree;
|
||||
submesh_aabb_tree(V,F,I,tree,triangles,in_I);
|
||||
|
||||
return closest_facet(
|
||||
V,F,I,P,EMAP,uEC,uEE,VF,VFi,tree,triangles,in_I,R,S);
|
||||
}
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename DerivedEMAP,
|
||||
typename DeriveduEC,
|
||||
typename DeriveduEE,
|
||||
typename DerivedR,
|
||||
typename DerivedS >
|
||||
IGL_INLINE void igl::copyleft::cgal::closest_facet(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
const Eigen::PlainObjectBase<DeriveduEC>& uEC,
|
||||
const Eigen::PlainObjectBase<DeriveduEE>& uEE,
|
||||
Eigen::PlainObjectBase<DerivedR>& R,
|
||||
Eigen::PlainObjectBase<DerivedS>& S) {
|
||||
const size_t num_faces = F.rows();
|
||||
Eigen::VectorXi I = igl::LinSpaced<Eigen::VectorXi>(num_faces, 0, num_faces-1);
|
||||
igl::copyleft::cgal::closest_facet(V, F, I, P, EMAP, uEC, uEE, R, S);
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::closest_facet<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -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>, CGAL::Epeck, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<size_t, std::allocator<size_t> >, std::allocator<std::vector<size_t, std::allocator<size_t> > > > const&, std::vector<std::vector<size_t, std::allocator<size_t> >, std::allocator<std::vector<size_t, std::allocator<size_t> > > > const&, CGAL::AABB_tree<CGAL::AABB_traits<CGAL::Epeck, CGAL::AABB_triangle_primitive<CGAL::Epeck, std::vector<CGAL::Epeck::Triangle_3, std::allocator<CGAL::Epeck::Triangle_3> >::iterator, CGAL::Boolean_tag<false> >, CGAL::Default> > const&, std::vector<CGAL::Epeck::Triangle_3, std::allocator<CGAL::Epeck::Triangle_3> > const&, std::vector<bool, std::allocator<bool> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#include <cstdint>
|
||||
template void igl::copyleft::cgal::closest_facet<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<CGAL::Epeck::FT, -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>, CGAL::Epeck, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<size_t, std::allocator<size_t> >, std::allocator<std::vector<size_t, std::allocator<size_t> > > > const&, std::vector<std::vector<size_t, std::allocator<size_t> >, std::allocator<std::vector<size_t, std::allocator<size_t> > > > const&, CGAL::AABB_tree<CGAL::AABB_traits<CGAL::Epeck, CGAL::AABB_triangle_primitive<CGAL::Epeck, std::vector<CGAL::Epeck::Triangle_3, std::allocator<CGAL::Epeck::Triangle_3> >::iterator, CGAL::Boolean_tag<false> >, CGAL::Default> > const&, std::vector<CGAL::Epeck::Triangle_3, std::allocator<CGAL::Epeck::Triangle_3> > const&, std::vector<bool, std::allocator<bool> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#ifdef WIN32
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,158 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@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_COPYLET_CGAL_CLOSEST_FACET_H
|
||||
#define IGL_COPYLET_CGAL_CLOSEST_FACET_H
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
|
||||
#include <CGAL/AABB_tree.h>
|
||||
#include <CGAL/AABB_traits.h>
|
||||
#include <CGAL/AABB_triangle_primitive.h>
|
||||
#include <CGAL/intersections.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
/// Determine the closest facet for each of the input points.
|
||||
///
|
||||
/// @param[in] V #V by 3 array of vertices.
|
||||
/// @param[in] F #F by 3 array of faces.
|
||||
/// @param[in] I #I list of triangle indices to consider.
|
||||
/// @param[in] P #P by 3 array of query points.
|
||||
/// @param[in] EMAP #F*3 list of indices into uE.
|
||||
/// @param[in] uEC #uE+1 list of cumsums of directed edges sharing each unique edge
|
||||
/// @param[in] uEE #E list of indices into E (see `igl::unique_edge_map`)
|
||||
/// @param[in] VF #V list of lists of incident faces (adjacency list)
|
||||
/// @param[in] VFi #V list of lists of index of incidence within incident faces listed in VF
|
||||
/// @param[in] tree AABB containing triangles of (V,F(I,:))
|
||||
/// @param[in] triangles #I list of cgal triangles
|
||||
/// @param[in] in_I #F list of whether in submesh
|
||||
/// @param[out] R #P list of closest facet indices.
|
||||
/// @param[out] S #P list of bools indicating on which side of the closest facet
|
||||
/// each query point lies.
|
||||
///
|
||||
/// \note The use of `size_t` here is a bad idea. These should just be int
|
||||
/// to avoid nonsense with windows.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename DerivedP,
|
||||
typename DerivedEMAP,
|
||||
typename DeriveduEC,
|
||||
typename DeriveduEE,
|
||||
typename Kernel,
|
||||
typename DerivedR,
|
||||
typename DerivedS >
|
||||
IGL_INLINE void closest_facet(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
const Eigen::PlainObjectBase<DeriveduEC>& uEC,
|
||||
const Eigen::PlainObjectBase<DeriveduEE>& uEE,
|
||||
const std::vector<std::vector<size_t> > & VF,
|
||||
const std::vector<std::vector<size_t> > & VFi,
|
||||
const CGAL::AABB_tree<
|
||||
CGAL::AABB_traits<
|
||||
Kernel,
|
||||
CGAL::AABB_triangle_primitive<
|
||||
Kernel, typename std::vector<
|
||||
typename Kernel::Triangle_3 >::iterator > > > & tree,
|
||||
const std::vector<typename Kernel::Triangle_3 > & triangles,
|
||||
const std::vector<bool> & in_I,
|
||||
Eigen::PlainObjectBase<DerivedR>& R,
|
||||
Eigen::PlainObjectBase<DerivedS>& S);
|
||||
/// \overload
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename DerivedP,
|
||||
typename DerivedEMAP,
|
||||
typename DeriveduEC,
|
||||
typename DeriveduEE,
|
||||
typename DerivedR,
|
||||
typename DerivedS >
|
||||
IGL_INLINE void closest_facet(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
const Eigen::PlainObjectBase<DeriveduEC>& uEC,
|
||||
const Eigen::PlainObjectBase<DeriveduEE>& uEE,
|
||||
Eigen::PlainObjectBase<DerivedR>& R,
|
||||
Eigen::PlainObjectBase<DerivedS>& S);
|
||||
/// \overload
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename DerivedEMAP,
|
||||
typename DeriveduEC,
|
||||
typename DeriveduEE,
|
||||
typename DerivedR,
|
||||
typename DerivedS >
|
||||
IGL_INLINE void closest_facet(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
const Eigen::PlainObjectBase<DeriveduEC>& uEC,
|
||||
const Eigen::PlainObjectBase<DeriveduEE>& uEE,
|
||||
Eigen::PlainObjectBase<DerivedR>& R,
|
||||
Eigen::PlainObjectBase<DerivedS>& S);
|
||||
/// \overload
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename DerivedP,
|
||||
typename DerivedEMAP,
|
||||
typename DeriveduEC,
|
||||
typename DeriveduEE,
|
||||
typename Kernel,
|
||||
typename DerivedR,
|
||||
typename DerivedS >
|
||||
IGL_INLINE void closest_facet(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
const Eigen::PlainObjectBase<DeriveduEC>& uEC,
|
||||
const Eigen::PlainObjectBase<DeriveduEE>& uEE,
|
||||
const std::vector<std::vector<size_t> > & VF,
|
||||
const std::vector<std::vector<size_t> > & VFi,
|
||||
const CGAL::AABB_tree<
|
||||
CGAL::AABB_traits<
|
||||
Kernel,
|
||||
CGAL::AABB_triangle_primitive<
|
||||
Kernel, typename std::vector<
|
||||
typename Kernel::Triangle_3 >::iterator > > > & tree,
|
||||
const std::vector<typename Kernel::Triangle_3 > & triangles,
|
||||
const std::vector<bool> & in_I,
|
||||
Eigen::PlainObjectBase<DerivedR>& R,
|
||||
Eigen::PlainObjectBase<DerivedS>& S);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
#include "closest_facet.cpp"
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,153 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 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 "complex_to_mesh.h"
|
||||
|
||||
#include "../../centroid.h"
|
||||
#include "../../remove_unreferenced.h"
|
||||
|
||||
#include <CGAL/Surface_mesh_default_triangulation_3.h>
|
||||
#include <CGAL/Delaunay_triangulation_cell_base_with_circumcenter_3.h>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
|
||||
template <typename Tr, typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE bool igl::copyleft::cgal::complex_to_mesh(
|
||||
const CGAL::Complex_2_in_triangulation_3<Tr> & c2t3,
|
||||
Eigen::PlainObjectBase<DerivedV> & V,
|
||||
Eigen::PlainObjectBase<DerivedF> & F)
|
||||
{
|
||||
using namespace Eigen;
|
||||
// CGAL/IO/Complex_2_in_triangulation_3_file_writer.h
|
||||
using CGAL::Surface_mesher::number_of_facets_on_surface;
|
||||
|
||||
typedef typename CGAL::Complex_2_in_triangulation_3<Tr> C2t3;
|
||||
typedef typename Tr::Finite_facets_iterator Finite_facets_iterator;
|
||||
typedef typename Tr::Finite_vertices_iterator Finite_vertices_iterator;
|
||||
typedef typename Tr::Facet Facet;
|
||||
typedef typename Tr::Edge Edge;
|
||||
typedef typename Tr::Vertex_handle Vertex_handle;
|
||||
|
||||
// Header.
|
||||
const Tr& tr = c2t3.triangulation();
|
||||
|
||||
bool success = true;
|
||||
|
||||
const int n = tr.number_of_vertices();
|
||||
const int m = c2t3.number_of_facets();
|
||||
|
||||
assert(m == number_of_facets_on_surface(tr));
|
||||
|
||||
// Finite vertices coordinates.
|
||||
std::map<Vertex_handle, int> v2i;
|
||||
V.resize(n,3);
|
||||
{
|
||||
int v = 0;
|
||||
for(Finite_vertices_iterator vit = tr.finite_vertices_begin();
|
||||
vit != tr.finite_vertices_end();
|
||||
++vit)
|
||||
{
|
||||
V(v,0) = vit->point().x();
|
||||
V(v,1) = vit->point().y();
|
||||
V(v,2) = vit->point().z();
|
||||
v2i[vit] = v++;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Finite_facets_iterator fit = tr.finite_facets_begin();
|
||||
std::set<Facet> oriented_set;
|
||||
std::stack<Facet> stack;
|
||||
|
||||
while ((int)oriented_set.size() != m)
|
||||
{
|
||||
while ( fit->first->is_facet_on_surface(fit->second) == false ||
|
||||
oriented_set.find(*fit) != oriented_set.end() ||
|
||||
oriented_set.find(c2t3.opposite_facet(*fit)) !=
|
||||
oriented_set.end() )
|
||||
{
|
||||
++fit;
|
||||
}
|
||||
oriented_set.insert(*fit);
|
||||
stack.push(*fit);
|
||||
while(! stack.empty() )
|
||||
{
|
||||
Facet f = stack.top();
|
||||
stack.pop();
|
||||
for(int ih = 0 ; ih < 3 ; ++ih)
|
||||
{
|
||||
const int i1 = tr.vertex_triple_index(f.second, tr. cw(ih));
|
||||
const int i2 = tr.vertex_triple_index(f.second, tr.ccw(ih));
|
||||
|
||||
const typename C2t3::Face_status face_status
|
||||
= c2t3.face_status(Edge(f.first, i1, i2));
|
||||
if(face_status == C2t3::REGULAR)
|
||||
{
|
||||
Facet fn = c2t3.neighbor(f, ih);
|
||||
if (oriented_set.find(fn) == oriented_set.end())
|
||||
{
|
||||
if(oriented_set.find(c2t3.opposite_facet(fn)) == oriented_set.end())
|
||||
{
|
||||
oriented_set.insert(fn);
|
||||
stack.push(fn);
|
||||
}else {
|
||||
success = false; // non-orientable
|
||||
}
|
||||
}
|
||||
}else if(face_status != C2t3::BOUNDARY)
|
||||
{
|
||||
success = false; // non manifold, thus non-orientable
|
||||
}
|
||||
} // end "for each neighbor of f"
|
||||
} // end "stack non empty"
|
||||
} // end "oriented_set not full"
|
||||
|
||||
F.resize(m,3);
|
||||
int f = 0;
|
||||
for(typename std::set<Facet>::const_iterator fit =
|
||||
oriented_set.begin();
|
||||
fit != oriented_set.end();
|
||||
++fit)
|
||||
{
|
||||
const typename Tr::Cell_handle cell = fit->first;
|
||||
const int& index = fit->second;
|
||||
const int index1 = v2i[cell->vertex(tr.vertex_triple_index(index, 0))];
|
||||
const int index2 = v2i[cell->vertex(tr.vertex_triple_index(index, 1))];
|
||||
const int index3 = v2i[cell->vertex(tr.vertex_triple_index(index, 2))];
|
||||
// This order is flipped
|
||||
F(f,0) = index1;
|
||||
F(f,1) = index2;
|
||||
F(f,2) = index3;
|
||||
f++;
|
||||
}
|
||||
assert(f == m);
|
||||
} // end if(facets must be oriented)
|
||||
|
||||
// This CGAL code seems to randomly assign the global orientation
|
||||
// Flip based on the signed volume.
|
||||
Eigen::Vector3d cen;
|
||||
double vol;
|
||||
igl::centroid(V,F,cen,vol);
|
||||
if(vol < 0)
|
||||
{
|
||||
// Flip
|
||||
F = F.rowwise().reverse().eval();
|
||||
}
|
||||
|
||||
// CGAL code somehow can end up with unreferenced vertices
|
||||
{
|
||||
VectorXi _1;
|
||||
remove_unreferenced( MatrixXd(V), MatrixXi(F), V,F,_1);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template bool igl::copyleft::cgal::complex_to_mesh<CGAL::Delaunay_triangulation_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_data_structure_3<CGAL::Surface_mesh_vertex_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_vertex_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_ds_vertex_base_3<void> > >, CGAL::Delaunay_triangulation_cell_base_with_circumcenter_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Surface_mesh_cell_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_cell_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_ds_cell_base_3<void> > > >, CGAL::Sequential_tag>, CGAL::Default, CGAL::Default>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(CGAL::Complex_2_in_triangulation_3<CGAL::Delaunay_triangulation_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_data_structure_3<CGAL::Surface_mesh_vertex_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_vertex_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_ds_vertex_base_3<void> > >, CGAL::Delaunay_triangulation_cell_base_with_circumcenter_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Surface_mesh_cell_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_cell_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_ds_cell_base_3<void> > > >, CGAL::Sequential_tag>, CGAL::Default, CGAL::Default>, void> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -1,45 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 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_COPYLEFT_CGAL_COMPLEX_TO_MESH_H
|
||||
#define IGL_COPYLEFT_CGAL_COMPLEX_TO_MESH_H
|
||||
#include "../../igl_inline.h"
|
||||
|
||||
#include <Eigen/Dense>
|
||||
#include <CGAL/Complex_2_in_triangulation_3.h>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
/// Convert a CGAL::Complex_2_in_triangulation_3 to a mesh (V,F)
|
||||
///
|
||||
/// @tparam Tr CGAL triangulation type, e.g. CGAL::Surface_mesh_default_triangulation_3
|
||||
/// @param[in] c2t3 2-complex (surface) living in a 3d triangulation
|
||||
/// (e.g. result of CGAL::make_surface_mesh)
|
||||
/// @param[out] V #V by 3 list of vertex positions
|
||||
/// @param[out] F #F by 3 list of triangle indices
|
||||
/// @return true iff conversion was successful, failure can ok if CGAL code
|
||||
/// can't figure out ordering.
|
||||
///
|
||||
template <typename Tr, typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE bool complex_to_mesh(
|
||||
const CGAL::Complex_2_in_triangulation_3<Tr> & c2t3,
|
||||
Eigen::PlainObjectBase<DerivedV> & V,
|
||||
Eigen::PlainObjectBase<DerivedF> & F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "complex_to_mesh.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@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 "component_inside_component.h"
|
||||
|
||||
#include "order_facets_around_edge.h"
|
||||
#include "../../LinSpaced.h"
|
||||
#include "points_inside_component.h"
|
||||
|
||||
#include <CGAL/AABB_tree.h>
|
||||
#include <CGAL/AABB_traits.h>
|
||||
#include <CGAL/AABB_triangle_primitive.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <list>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedI>
|
||||
IGL_INLINE bool igl::copyleft::cgal::component_inside_component(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V1,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F1,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I1,
|
||||
const Eigen::PlainObjectBase<DerivedV>& V2,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F2,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I2) {
|
||||
if (F1.rows() <= 0 || I1.rows() <= 0 || F2.rows() <= 0 || I2.rows() <= 0) {
|
||||
throw "Component inside test cannot be done on empty component!";
|
||||
}
|
||||
|
||||
const Eigen::Vector3i& f = F1.row(I1(0, 0));
|
||||
const Eigen::Matrix<typename DerivedV::Scalar, 1, 3> query(
|
||||
(V1(f[0],0) + V1(f[1],0) + V1(f[2],0))/3.0,
|
||||
(V1(f[0],1) + V1(f[1],1) + V1(f[2],1))/3.0,
|
||||
(V1(f[0],2) + V1(f[1],2) + V1(f[2],2))/3.0);
|
||||
Eigen::VectorXi inside;
|
||||
igl::copyleft::cgal::points_inside_component(V2, F2, I2, query, inside);
|
||||
assert(inside.size() == 1);
|
||||
return inside[0];
|
||||
}
|
||||
|
||||
template<typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE bool igl::copyleft::cgal::component_inside_component(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V1,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F1,
|
||||
const Eigen::PlainObjectBase<DerivedV>& V2,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F2) {
|
||||
if (F1.rows() <= 0 || F2.rows() <= 0) {
|
||||
throw "Component inside test cannot be done on empty component!";
|
||||
}
|
||||
Eigen::VectorXi I1(F1.rows()), I2(F2.rows());
|
||||
I1 = igl::LinSpaced<Eigen::VectorXi>(F1.rows(), 0, F1.rows()-1);
|
||||
I2 = igl::LinSpaced<Eigen::VectorXi>(F2.rows(), 0, F2.rows()-1);
|
||||
return igl::copyleft::cgal::component_inside_component(V1, F1, I1, V2, F2, I2);
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template bool igl::copyleft::cgal::component_inside_component<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::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&,Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&,Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&,Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&,Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&,Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&);
|
||||
template bool igl::copyleft::cgal::component_inside_component<Eigen::Matrix<double, -1, -1, 0, -1, -1>,Eigen::Matrix< int, -1, -1, 0, -1, -1> > (Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&,Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&,Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&,Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&);
|
||||
#endif
|
||||
@@ -1,56 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@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_COPYLEFT_CGAL_COMONENT_INSIDE_COMPONENT
|
||||
#define IGL_COPYLEFT_CGAL_COMONENT_INSIDE_COMPONENT
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
|
||||
namespace igl {
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
/// Determine if connected facet component (V1, F1, I1) is inside of
|
||||
/// connected facet component (V2, F2, I2).
|
||||
///
|
||||
/// \pre Both components must represent closed, self-intersection free,
|
||||
/// non-degenerated surfaces that are the boundary of 3D volumes. In
|
||||
/// addition, (V1, F1, I1) must not intersect with (V2, F2, I2).
|
||||
///
|
||||
/// @param[in] V1 #V1 by 3 list of vertex position of mesh 1
|
||||
/// @param[in] F1 #F1 by 3 list of triangles indices into V1
|
||||
/// @param[in] I1 #I1 list of indices into F1, indicate the facets of component
|
||||
/// @param[in] V2 #V2 by 3 list of vertex position of mesh 2
|
||||
/// @param[in] F2 #F2 by 3 list of triangles indices into V2
|
||||
/// @param[in] I2 #I2 list of indices into F2, indicate the facets of component
|
||||
/// @return true iff (V1, F1, I1) is entirely inside of (V2, F2, I2).
|
||||
template<typename DerivedV, typename DerivedF, typename DerivedI>
|
||||
IGL_INLINE bool component_inside_component(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V1,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F1,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I1,
|
||||
const Eigen::PlainObjectBase<DerivedV>& V2,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F2,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I2);
|
||||
/// \overload
|
||||
template<typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE bool component_inside_component(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V1,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F1,
|
||||
const Eigen::PlainObjectBase<DerivedV>& V2,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
#include "component_inside_component.cpp"
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,103 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2017 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 "convex_hull.h"
|
||||
#include "../../ismember_rows.h"
|
||||
#include "polyhedron_to_mesh.h"
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include <CGAL/convex_hull_3.h>
|
||||
#include <vector>
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedW,
|
||||
typename DerivedG>
|
||||
IGL_INLINE void igl::copyleft::cgal::convex_hull(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::PlainObjectBase<DerivedW> & W,
|
||||
Eigen::PlainObjectBase<DerivedG> & G)
|
||||
{
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
switch(V.cols())
|
||||
{
|
||||
case 3:
|
||||
{
|
||||
typedef K::Point_3 Point_3;
|
||||
//typedef CGAL::Delaunay_triangulation_3<K> Delaunay;
|
||||
//typedef Delaunay::Vertex_handle Vertex_handle;
|
||||
//typedef CGAL::Surface_mesh<Point_3> Surface_mesh;
|
||||
typedef CGAL::Polyhedron_3<K> Polyhedron_3;
|
||||
std::vector<Point_3> points(V.rows());
|
||||
for(int i = 0;i<V.rows();i++)
|
||||
{
|
||||
points[i] = Point_3(V(i,0),V(i,1),V(i,2));
|
||||
}
|
||||
Polyhedron_3 poly;
|
||||
CGAL::convex_hull_3(points.begin(),points.end(),poly);
|
||||
assert(poly.is_pure_triangle() && "Assuming CGAL outputs a triangle mesh");
|
||||
polyhedron_to_mesh(poly,W,G);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
typedef K::Point_2 Point_2;
|
||||
std::vector<Point_2> points(V.rows());
|
||||
std::vector<Point_2> result;
|
||||
for(int i = 0;i<V.rows();i++)
|
||||
{
|
||||
points[i] = Point_2(V(i,0),V(i,1));
|
||||
}
|
||||
CGAL::convex_hull_2(points.begin(),points.end(),std::back_inserter(result));
|
||||
W.resize(result.size(),2);
|
||||
G.resize(result.size(),2);
|
||||
for(int i = 0;i<result.size();i++)
|
||||
{
|
||||
W(i,0) = result[i].x();
|
||||
W(i,1) = result[i].y();
|
||||
G(i,0) = i;
|
||||
G(i,1) = (i+1)%result.size();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF>
|
||||
IGL_INLINE void igl::copyleft::cgal::convex_hull(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::PlainObjectBase<DerivedF> & F)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic> W;
|
||||
Eigen::Matrix<typename DerivedF::Scalar, Eigen::Dynamic, Eigen::Dynamic> G;
|
||||
convex_hull(V,W,G);
|
||||
// This is a lazy way to reindex into the original mesh
|
||||
Eigen::Matrix<bool,Eigen::Dynamic,1> I;
|
||||
Eigen::VectorXi J;
|
||||
igl::ismember_rows(W,V,I,J);
|
||||
assert(I.all() && "Should find all W in V");
|
||||
F.resizeLike(G);
|
||||
for(int f = 0;f<G.rows();f++)
|
||||
{
|
||||
for(int c = 0;c<3;c++)
|
||||
{
|
||||
F(f,c) = J(G(f,c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::copyleft::cgal::convex_hull<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::convex_hull<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::convex_hull<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::convex_hull<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -1,47 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2017 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_COPYLEFT_CGAL_CONVEX_HULL_H
|
||||
#define IGL_COPYLEFT_CGAL_CONVEX_HULL_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
/// Given a set of points (V), compute the convex hull as a triangle mesh (W,G)
|
||||
///
|
||||
/// @param[in] V #V by 3 list of input points
|
||||
/// @param[out] W #W by 3 list of convex hull points
|
||||
/// @param[out] G #G by 3 list of triangle indices into W
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedW,
|
||||
typename DerivedG>
|
||||
IGL_INLINE void convex_hull(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::PlainObjectBase<DerivedW> & W,
|
||||
Eigen::PlainObjectBase<DerivedG> & G);
|
||||
/// \overload
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF>
|
||||
IGL_INLINE void convex_hull(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::PlainObjectBase<DerivedF> & F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "convex_hull.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,48 +0,0 @@
|
||||
#include "coplanar.h"
|
||||
#include "row_to_point.h"
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Point_3.h>
|
||||
|
||||
template <typename DerivedV>
|
||||
IGL_INLINE bool igl::copyleft::cgal::coplanar(
|
||||
const Eigen::MatrixBase<DerivedV> & V)
|
||||
{
|
||||
// 3 points in 3D are always coplanar
|
||||
if(V.rows() < 4){ return true; }
|
||||
// spanning points found so far
|
||||
std::vector<CGAL::Point_3<CGAL::Epick> > p;
|
||||
for(int i = 0;i<V.rows();i++)
|
||||
{
|
||||
const CGAL::Point_3<CGAL::Epick> pi(V(i,0), V(i,1), V(i,2));
|
||||
switch(p.size())
|
||||
{
|
||||
case 0:
|
||||
p.push_back(pi);
|
||||
break;
|
||||
case 1:
|
||||
if(p[0] != pi)
|
||||
{
|
||||
p.push_back(pi);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if(!CGAL::collinear(p[0],p[1],pi))
|
||||
{
|
||||
p.push_back(pi);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if(!CGAL::coplanar(p[0],p[1],p[2],pi))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template bool igl::copyleft::cgal::coplanar<Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&);
|
||||
#endif
|
||||
@@ -1,25 +0,0 @@
|
||||
#ifndef IGL_COPYLEFT_CGAL_COPLANAR_H
|
||||
#define IGL_COPYLEFT_CGAL_COPLANAR_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
/// Test whether all points are on same plane.
|
||||
///
|
||||
/// @param[in] V #V by 3 list of 3D vertex positions
|
||||
/// @return true if all points lie on the same plane
|
||||
template <typename DerivedV>
|
||||
IGL_INLINE bool coplanar(
|
||||
const Eigen::MatrixBase<DerivedV> & V);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "coplanar.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,67 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2018 Alec Jacobson
|
||||
// Copyright (C) 2016 Qingnan Zhou <qnzhou@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 "delaunay_triangulation.h"
|
||||
#include "../../delaunay_triangulation.h"
|
||||
#include "orient2D.h"
|
||||
#include "incircle.h"
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF>
|
||||
IGL_INLINE void igl::copyleft::cgal::delaunay_triangulation(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
Eigen::PlainObjectBase<DerivedF>& F)
|
||||
{
|
||||
typedef typename DerivedV::Scalar Scalar;
|
||||
igl::delaunay_triangulation(V, orient2D<Scalar>, incircle<Scalar>, F);
|
||||
// This function really exists to test our igl::delaunay_triangulation
|
||||
//
|
||||
// It's currently much faster to call cgal's native Delaunay routine
|
||||
//
|
||||
//#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
//#include <CGAL/Delaunay_triangulation_2.h>
|
||||
//#include <CGAL/Triangulation_vertex_base_with_info_2.h>
|
||||
//#include <vector>
|
||||
// const auto delaunay =
|
||||
// [&](const Eigen::MatrixXd & V,Eigen::MatrixXi & F)
|
||||
// {
|
||||
// typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||
// typedef CGAL::Triangulation_vertex_base_with_info_2<unsigned int, Kernel> Vb;
|
||||
// typedef CGAL::Triangulation_data_structure_2<Vb> Tds;
|
||||
// typedef CGAL::Delaunay_triangulation_2<Kernel, Tds> Delaunay;
|
||||
// typedef Kernel::Point_2 Point;
|
||||
// std::vector< std::pair<Point,unsigned> > points(V.rows());
|
||||
// for(int i = 0;i<V.rows();i++)
|
||||
// {
|
||||
// points[i] = std::make_pair(Point(V(i,0),V(i,1)),i);
|
||||
// }
|
||||
// Delaunay triangulation;
|
||||
// triangulation.insert(points.begin(),points.end());
|
||||
// F.resize(triangulation.number_of_faces(),3);
|
||||
// {
|
||||
// int j = 0;
|
||||
// for(Delaunay::Finite_faces_iterator fit = triangulation.finite_faces_begin();
|
||||
// fit != triangulation.finite_faces_end(); ++fit)
|
||||
// {
|
||||
// Delaunay::Face_handle face = fit;
|
||||
// F(j,0) = face->vertex(0)->info();
|
||||
// F(j,1) = face->vertex(1)->info();
|
||||
// F(j,2) = face->vertex(2)->info();
|
||||
// j++;
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::delaunay_triangulation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -1,43 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Qingan Zhou <qnzhou@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_COPYLEFT_CGAL_DELAUNAY_TRIANGULATION_H
|
||||
#define IGL_COPYLEFT_CGAL_DELAUNAY_TRIANGULATION_H
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
/// Given a set of points in 2D, return a Delaunay triangulation of these
|
||||
/// points.
|
||||
///
|
||||
/// @param[in] V #V by 2 list of vertex positions
|
||||
/// @param[out] F #F by 3 of faces in Delaunay triangulation.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF
|
||||
>
|
||||
IGL_INLINE void delaunay_triangulation(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
Eigen::PlainObjectBase<DerivedF>& F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "delaunay_triangulation.cpp"
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,397 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@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 "extract_cells.h"
|
||||
#include "extract_cells_single_component.h"
|
||||
#include "closest_facet.h"
|
||||
#include "outer_facet.h"
|
||||
#include "submesh_aabb_tree.h"
|
||||
#include "../../extract_manifold_patches.h"
|
||||
#include "../../facet_components.h"
|
||||
#include "../../parallel_for.h"
|
||||
#include "../../get_seconds.h"
|
||||
#include "../../triangle_triangle_adjacency.h"
|
||||
#include "../../unique_edge_map.h"
|
||||
#include "../../C_STR.h"
|
||||
#include "../../vertex_triangle_adjacency.h"
|
||||
|
||||
#include <CGAL/AABB_tree.h>
|
||||
#include <CGAL/AABB_traits.h>
|
||||
#include <CGAL/AABB_triangle_primitive.h>
|
||||
#include <CGAL/intersections.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
//#define EXTRACT_CELLS_TIMING
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedC >
|
||||
IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedC>& cells)
|
||||
{
|
||||
const size_t num_faces = F.rows();
|
||||
// Construct edge adjacency
|
||||
Eigen::MatrixXi E, uE;
|
||||
Eigen::VectorXi EMAP;
|
||||
Eigen::VectorXi uEC,uEE;
|
||||
igl::unique_edge_map(F, E, uE, EMAP, uEC, uEE);
|
||||
// Cluster into manifold patches
|
||||
Eigen::VectorXi P;
|
||||
igl::extract_manifold_patches(F, EMAP, uEC, uEE, P);
|
||||
// Extract cells
|
||||
DerivedC per_patch_cells;
|
||||
const size_t ncells = extract_cells(V,F,P,E,uE,EMAP,uEC,uEE,per_patch_cells);
|
||||
// Distribute per-patch cell information to each face
|
||||
cells.resize(num_faces, 2);
|
||||
for (size_t i=0; i<num_faces; i++)
|
||||
{
|
||||
cells.row(i) = per_patch_cells.row(P[i]);
|
||||
}
|
||||
return ncells;
|
||||
}
|
||||
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename DerivedE,
|
||||
typename DeriveduE,
|
||||
typename DerivedEMAP,
|
||||
typename DeriveduEC,
|
||||
typename DeriveduEE,
|
||||
typename DerivedC >
|
||||
IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const Eigen::PlainObjectBase<DerivedE>& E,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
const Eigen::PlainObjectBase<DeriveduEC>& uEC,
|
||||
const Eigen::PlainObjectBase<DeriveduEE>& uEE,
|
||||
Eigen::PlainObjectBase<DerivedC>& cells)
|
||||
{
|
||||
// Trivial base case
|
||||
if(P.size() == 0)
|
||||
{
|
||||
assert(F.size() == 0);
|
||||
cells.resize(0,2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
|
||||
typedef Kernel::Point_3 Point_3;
|
||||
typedef Kernel::Plane_3 Plane_3;
|
||||
typedef Kernel::Segment_3 Segment_3;
|
||||
typedef Kernel::Triangle_3 Triangle;
|
||||
typedef std::vector<Triangle>::iterator Iterator;
|
||||
typedef CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
|
||||
typedef CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
|
||||
typedef CGAL::AABB_tree<AABB_triangle_traits> Tree;
|
||||
|
||||
#ifdef EXTRACT_CELLS_TIMING
|
||||
const auto & tictoc = []() -> double
|
||||
{
|
||||
static double t_start = igl::get_seconds();
|
||||
double diff = igl::get_seconds()-t_start;
|
||||
t_start += diff;
|
||||
return diff;
|
||||
};
|
||||
const auto log_time = [&](const std::string& label) -> void {
|
||||
printf("%50s: %0.5lf\n",
|
||||
C_STR("extract_cells." << label),tictoc());
|
||||
};
|
||||
tictoc();
|
||||
#else
|
||||
// no-op
|
||||
const auto log_time = [](const std::string){};
|
||||
#endif
|
||||
const size_t num_faces = F.rows();
|
||||
typedef typename DerivedF::Scalar Index;
|
||||
assert(P.size() > 0);
|
||||
const size_t num_patches = P.maxCoeff()+1;
|
||||
|
||||
// Extract all cells...
|
||||
DerivedC raw_cells;
|
||||
const size_t num_raw_cells =
|
||||
extract_cells_single_component(V,F,P,uE,EMAP,uEC,uEE,raw_cells);
|
||||
log_time("extract_cells_single_component");
|
||||
|
||||
// Compute triangle-triangle adjacency data-structure
|
||||
std::vector<std::vector<std::vector<Index > > > TT,_1;
|
||||
igl::triangle_triangle_adjacency(EMAP, uEC, uEE, false, TT, _1);
|
||||
log_time("compute_face_adjacency");
|
||||
|
||||
// Compute connected components of the mesh
|
||||
Eigen::VectorXi C, counts;
|
||||
igl::facet_components(TT, C, counts);
|
||||
log_time("form_components");
|
||||
|
||||
const size_t num_components = counts.size();
|
||||
// components[c] --> list of face indices into F of faces in component c
|
||||
std::vector<std::vector<size_t> > components(num_components);
|
||||
// Loop over all faces
|
||||
for (size_t i=0; i<num_faces; i++)
|
||||
{
|
||||
components[C[i]].push_back(i);
|
||||
}
|
||||
// Convert vector lists to Eigen lists...
|
||||
// and precompute data-structures for each component
|
||||
std::vector<std::vector<size_t> > VF,VFi;
|
||||
igl::vertex_triangle_adjacency(V.rows(), F, VF, VFi);
|
||||
std::vector<Eigen::VectorXi> Is(num_components);
|
||||
std::vector<
|
||||
CGAL::AABB_tree<
|
||||
CGAL::AABB_traits<
|
||||
Kernel,
|
||||
CGAL::AABB_triangle_primitive<
|
||||
Kernel, std::vector<
|
||||
Kernel::Triangle_3 >::iterator > > > > trees(num_components);
|
||||
std::vector< std::vector<Kernel::Triangle_3 > >
|
||||
triangle_lists(num_components);
|
||||
// O(num_components * num_faces)
|
||||
// In general, extract_cells appears to have O(num_components * num_faces)
|
||||
// performance. This could be painfully tested by a processing a cloud of
|
||||
// tetrahedra.
|
||||
std::vector<std::vector<bool> > in_Is(num_components);
|
||||
|
||||
// Find outer facets, their orientations and cells for each component
|
||||
Eigen::VectorXi outer_facets(num_components);
|
||||
Eigen::VectorXi outer_facet_orientation(num_components);
|
||||
Eigen::VectorXi outer_cells(num_components);
|
||||
igl::parallel_for(num_components,[&](size_t i)
|
||||
{
|
||||
Is[i].resize(components[i].size());
|
||||
std::copy(components[i].begin(), components[i].end(),Is[i].data());
|
||||
bool flipped;
|
||||
igl::copyleft::cgal::outer_facet(V, F, Is[i], outer_facets[i], flipped);
|
||||
outer_facet_orientation[i] = flipped?1:0;
|
||||
outer_cells[i] = raw_cells(P[outer_facets[i]], outer_facet_orientation[i]);
|
||||
},1000);
|
||||
#ifdef EXTRACT_CELLS_TIMING
|
||||
log_time("outer_facet_per_component");
|
||||
#endif
|
||||
|
||||
// Compute barycenter of a triangle in mesh (V,F)
|
||||
//
|
||||
// Inputs:
|
||||
// fid index into F
|
||||
// Returns row-vector of barycenter coordinates
|
||||
const auto get_triangle_center = [&V,&F](const size_t fid)
|
||||
{
|
||||
return ((V.row(F(fid,0))+V.row(F(fid,1))+V.row(F(fid,2)))/3.0).eval();
|
||||
};
|
||||
std::vector<std::vector<size_t> > nested_cells(num_raw_cells);
|
||||
std::vector<std::vector<size_t> > ambient_cells(num_raw_cells);
|
||||
std::vector<std::vector<size_t> > ambient_comps(num_components);
|
||||
// Only bother if there's more than one component
|
||||
if(num_components > 1)
|
||||
{
|
||||
// construct bounding boxes for each component
|
||||
DerivedV bbox_min(num_components, 3);
|
||||
DerivedV bbox_max(num_components, 3);
|
||||
// Assuming our mesh (in exact numbers) fits in the range of double.
|
||||
bbox_min.setConstant(std::numeric_limits<double>::max());
|
||||
bbox_max.setConstant(std::numeric_limits<double>::lowest());
|
||||
// Loop over faces
|
||||
for (size_t i=0; i<num_faces; i++)
|
||||
{
|
||||
// component of this face
|
||||
const auto comp_id = C[i];
|
||||
const auto& f = F.row(i);
|
||||
for (size_t j=0; j<3; j++)
|
||||
{
|
||||
for(size_t d=0;d<3;d++)
|
||||
{
|
||||
bbox_min(comp_id,d) = std::min(bbox_min(comp_id,d), V(f[j],d));
|
||||
bbox_max(comp_id,d) = std::max(bbox_max(comp_id,d), V(f[j],d));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return true if box of component ci intersects that of cj
|
||||
const auto bbox_intersects = [&bbox_max,&bbox_min](size_t ci, size_t cj)
|
||||
{
|
||||
return !(
|
||||
bbox_max(ci,0) < bbox_min(cj,0) ||
|
||||
bbox_max(ci,1) < bbox_min(cj,1) ||
|
||||
bbox_max(ci,2) < bbox_min(cj,2) ||
|
||||
bbox_max(cj,0) < bbox_min(ci,0) ||
|
||||
bbox_max(cj,1) < bbox_min(ci,1) ||
|
||||
bbox_max(cj,2) < bbox_min(ci,2));
|
||||
};
|
||||
|
||||
// Loop over components. This section is O(m²)
|
||||
for (size_t i=0; i<num_components; i++)
|
||||
{
|
||||
// List of components that could overlap with component i
|
||||
std::vector<size_t> candidate_comps;
|
||||
candidate_comps.reserve(num_components);
|
||||
// Loop over components
|
||||
for (size_t j=0; j<num_components; j++)
|
||||
{
|
||||
if (i == j) continue;
|
||||
if (bbox_intersects(i,j)) candidate_comps.push_back(j);
|
||||
}
|
||||
|
||||
const size_t num_candidate_comps = candidate_comps.size();
|
||||
if (num_candidate_comps == 0) continue;
|
||||
|
||||
// Build aabb tree for this component.
|
||||
submesh_aabb_tree(V,F,Is[i],trees[i],triangle_lists[i],in_Is[i]);
|
||||
|
||||
// Get query points on each candidate component: barycenter of
|
||||
// outer-facet
|
||||
DerivedV queries(num_candidate_comps, 3);
|
||||
for (size_t j=0; j<num_candidate_comps; j++)
|
||||
{
|
||||
const size_t index = candidate_comps[j];
|
||||
queries.row(j) = get_triangle_center(outer_facets[index]);
|
||||
}
|
||||
|
||||
// Gather closest facets in ith component to each query point and their
|
||||
// orientations
|
||||
const auto& I = Is[i];
|
||||
const auto& tree = trees[i];
|
||||
const auto& in_I = in_Is[i];
|
||||
const auto& triangles = triangle_lists[i];
|
||||
|
||||
Eigen::VectorXi closest_facets, closest_facet_orientations;
|
||||
closest_facet(
|
||||
V,
|
||||
F,
|
||||
I,
|
||||
queries,
|
||||
EMAP,
|
||||
uEC,
|
||||
uEE,
|
||||
VF,
|
||||
VFi,
|
||||
tree,
|
||||
triangles,
|
||||
in_I,
|
||||
closest_facets,
|
||||
closest_facet_orientations);
|
||||
// Loop over all candidates
|
||||
for (size_t j=0; j<num_candidate_comps; j++)
|
||||
{
|
||||
const size_t index = candidate_comps[j];
|
||||
const size_t closest_patch = P[closest_facets[j]];
|
||||
const size_t closest_patch_side = closest_facet_orientations[j] ? 0:1;
|
||||
// The cell id of the closest patch
|
||||
const size_t ambient_cell =
|
||||
raw_cells(closest_patch,closest_patch_side);
|
||||
if (ambient_cell != (size_t)outer_cells[i])
|
||||
{
|
||||
// ---> component index inside component i, because the cell of the
|
||||
// closest facet on i to component index is **not** the same as the
|
||||
// "outer cell" of component i: component index is **not** outside of
|
||||
// component i (therefore it's inside).
|
||||
nested_cells[ambient_cell].push_back(outer_cells[index]);
|
||||
ambient_cells[outer_cells[index]].push_back(ambient_cell);
|
||||
ambient_comps[index].push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef EXTRACT_CELLS_TIMING
|
||||
log_time("nested_relationship");
|
||||
#endif
|
||||
|
||||
const size_t INVALID = std::numeric_limits<size_t>::max();
|
||||
const size_t INFINITE_CELL = num_raw_cells;
|
||||
std::vector<size_t> embedded_cells(num_raw_cells, INVALID);
|
||||
for (size_t i=0; i<num_components; i++) {
|
||||
const size_t outer_cell = outer_cells[i];
|
||||
const auto& ambient_comps_i = ambient_comps[i];
|
||||
const auto& ambient_cells_i = ambient_cells[outer_cell];
|
||||
const size_t num_ambient_comps = ambient_comps_i.size();
|
||||
assert(num_ambient_comps == ambient_cells_i.size());
|
||||
if (num_ambient_comps > 0) {
|
||||
size_t embedded_comp = INVALID;
|
||||
size_t embedded_cell = INVALID;
|
||||
for (size_t j=0; j<num_ambient_comps; j++) {
|
||||
if (ambient_comps[ambient_comps_i[j]].size() ==
|
||||
num_ambient_comps-1) {
|
||||
embedded_comp = ambient_comps_i[j];
|
||||
embedded_cell = ambient_cells_i[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(embedded_comp != INVALID);
|
||||
assert(embedded_cell != INVALID);
|
||||
embedded_cells[outer_cell] = embedded_cell;
|
||||
} else {
|
||||
embedded_cells[outer_cell] = INFINITE_CELL;
|
||||
}
|
||||
}
|
||||
for (size_t i=0; i<num_patches; i++) {
|
||||
if (embedded_cells[raw_cells(i,0)] != INVALID) {
|
||||
raw_cells(i,0) = embedded_cells[raw_cells(i, 0)];
|
||||
}
|
||||
if (embedded_cells[raw_cells(i,1)] != INVALID) {
|
||||
raw_cells(i,1) = embedded_cells[raw_cells(i, 1)];
|
||||
}
|
||||
}
|
||||
|
||||
size_t count = 0;
|
||||
std::vector<size_t> mapped_indices(num_raw_cells+1, INVALID);
|
||||
// Always map infinite cell to index 0.
|
||||
mapped_indices[INFINITE_CELL] = count;
|
||||
count++;
|
||||
|
||||
for (size_t i=0; i<num_patches; i++) {
|
||||
const size_t old_positive_cell_id = raw_cells(i, 0);
|
||||
const size_t old_negative_cell_id = raw_cells(i, 1);
|
||||
size_t positive_cell_id, negative_cell_id;
|
||||
if (mapped_indices[old_positive_cell_id] == INVALID) {
|
||||
mapped_indices[old_positive_cell_id] = count;
|
||||
positive_cell_id = count;
|
||||
count++;
|
||||
} else {
|
||||
positive_cell_id = mapped_indices[old_positive_cell_id];
|
||||
}
|
||||
if (mapped_indices[old_negative_cell_id] == INVALID) {
|
||||
mapped_indices[old_negative_cell_id] = count;
|
||||
negative_cell_id = count;
|
||||
count++;
|
||||
} else {
|
||||
negative_cell_id = mapped_indices[old_negative_cell_id];
|
||||
}
|
||||
raw_cells(i, 0) = positive_cell_id;
|
||||
raw_cells(i, 1) = negative_cell_id;
|
||||
}
|
||||
cells = raw_cells;
|
||||
#ifdef EXTRACT_CELLS_TIMING
|
||||
log_time("finalize");
|
||||
#endif
|
||||
return count;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template size_t igl::copyleft::cgal::extract_cells<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -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<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template size_t igl::copyleft::cgal::extract_cells<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template size_t igl::copyleft::cgal::extract_cells<Eigen::Matrix<CGAL::Epeck::FT, -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<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
#ifdef WIN32
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,72 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@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_COPYLEFT_CGAL_EXTRACT_CELLS_H
|
||||
#define IGL_COPYLEFT_CGAL_EXTRACT_CELLS_H
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
|
||||
namespace igl {
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
/// Extract connected 3D space partitioned by mesh (V, F).
|
||||
///
|
||||
/// @param[in] V #V by 3 array of vertices.
|
||||
/// @param[in] F #F by 3 array of faces.
|
||||
/// @param[in] P #F list of patch indices.
|
||||
/// @param[in] E #E by 2 array of vertex indices, one edge per row.
|
||||
/// @param[in] uE #uE by 2 list of vertex_indices, represents undirected edges.
|
||||
/// @param[in] EMAP #F*3 list of indices into uE.
|
||||
/// @param[in] uEC #uE+1 list of cumsums of directed edges sharing each unique edge
|
||||
/// @param[in] uEE #E list of indices into E (see `igl::unique_edge_map`)
|
||||
/// @param[out] cells #F by 2 array of cell indices. cells(i,0) represents the
|
||||
/// cell index on the positive side of face i, and cells(i,1)
|
||||
/// represents cell index of the negqtive side.
|
||||
/// By convension cell with index 0 is the infinite cell.
|
||||
/// @return the number of cells
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename DerivedE,
|
||||
typename DeriveduE,
|
||||
typename DerivedEMAP,
|
||||
typename DeriveduEC,
|
||||
typename DeriveduEE,
|
||||
typename DerivedC >
|
||||
IGL_INLINE size_t extract_cells(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const Eigen::PlainObjectBase<DerivedE>& E,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
const Eigen::PlainObjectBase<DeriveduEC>& uEC,
|
||||
const Eigen::PlainObjectBase<DeriveduEE>& uEE,
|
||||
Eigen::PlainObjectBase<DerivedC>& cells);
|
||||
/// \overload
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedC >
|
||||
IGL_INLINE size_t extract_cells(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedC>& cells);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "extract_cells.cpp"
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,233 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@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 "extract_cells_single_component.h"
|
||||
#include "order_facets_around_edge.h"
|
||||
#include "../../C_STR.h"
|
||||
#include "../../get_seconds.h"
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
|
||||
//#define EXTRACT_CELLS_SINGLE_COMPONENT_TIMING
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename DeriveduE,
|
||||
typename DerivedEMAP,
|
||||
typename DeriveduEC,
|
||||
typename DeriveduEE,
|
||||
typename DerivedC>
|
||||
IGL_INLINE size_t igl::copyleft::cgal::extract_cells_single_component(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
const Eigen::PlainObjectBase<DeriveduEC>& uEC,
|
||||
const Eigen::PlainObjectBase<DeriveduEE>& uEE,
|
||||
Eigen::PlainObjectBase<DerivedC>& cells)
|
||||
{
|
||||
#ifdef EXTRACT_CELLS_SINGLE_COMPONENT_TIMING
|
||||
const auto & tictoc = []() -> double
|
||||
{
|
||||
static double t_start = igl::get_seconds();
|
||||
double diff = igl::get_seconds()-t_start;
|
||||
t_start += diff;
|
||||
return diff;
|
||||
};
|
||||
const auto log_time = [&](const std::string& label) -> void {
|
||||
printf("%50s: %0.5lf\n",
|
||||
C_STR("extrac*_single_component." << label),tictoc());
|
||||
};
|
||||
tictoc();
|
||||
#else
|
||||
// no-op
|
||||
const auto log_time = [](const std::string){};
|
||||
#endif
|
||||
const size_t num_faces = F.rows();
|
||||
// Input:
|
||||
// index index into #F*3 list of undirect edges
|
||||
// Returns index into face
|
||||
const auto e2f = [&num_faces](size_t index) { return index % num_faces; };
|
||||
// Determine if a face (containing undirected edge {s,d} is consistently
|
||||
// oriented with directed edge {s,d} (or otherwise it is with {d,s})
|
||||
//
|
||||
// Inputs:
|
||||
// fid face index into F
|
||||
// s source index of edge
|
||||
// d destination index of edge
|
||||
// Returns true if face F(fid,:) is consistent with {s,d}
|
||||
const auto is_consistent =
|
||||
[&F](const size_t fid, const size_t s, const size_t d) -> bool
|
||||
{
|
||||
if ((size_t)F(fid, 0) == s && (size_t)F(fid, 1) == d) return false;
|
||||
if ((size_t)F(fid, 1) == s && (size_t)F(fid, 2) == d) return false;
|
||||
if ((size_t)F(fid, 2) == s && (size_t)F(fid, 0) == d) return false;
|
||||
|
||||
if ((size_t)F(fid, 0) == d && (size_t)F(fid, 1) == s) return true;
|
||||
if ((size_t)F(fid, 1) == d && (size_t)F(fid, 2) == s) return true;
|
||||
if ((size_t)F(fid, 2) == d && (size_t)F(fid, 0) == s) return true;
|
||||
throw "Invalid face!";
|
||||
return false;
|
||||
};
|
||||
|
||||
const size_t num_unique_edges = uE.rows();
|
||||
const size_t num_patches = P.maxCoeff() + 1;
|
||||
|
||||
// Build patch-patch adjacency list.
|
||||
//
|
||||
// Does this really need to be a map? Or do I just want a list of neighbors
|
||||
// and for each neighbor an index to a unique edge? (i.e., a sparse matrix)
|
||||
std::vector<std::map<size_t, size_t> > patch_adj(num_patches);
|
||||
for (size_t i=0; i<num_unique_edges; i++)
|
||||
{
|
||||
const size_t s = uE(i,0);
|
||||
const size_t d = uE(i,1);
|
||||
//const auto adj_faces = uE2E[i];
|
||||
//const size_t num_adj_faces = adj_faces.size();
|
||||
const size_t num_adj_faces = uEC(i+1)-uEC(i);
|
||||
if (num_adj_faces > 2)
|
||||
{
|
||||
//for (size_t j=0; j<num_adj_faces; j++) {
|
||||
// const auto aj = adj_faces[j];
|
||||
for (size_t ij=uEC(i); ij<uEC(i+1); ij++)
|
||||
{
|
||||
const auto aj = uEE(ij);
|
||||
const size_t patch_j = P[e2f(aj)];
|
||||
//for (size_t k=j+1; k<num_adj_faces; k++) {
|
||||
// const auto ak = adj_faces[k];
|
||||
for (size_t ik=ij+1; ik<uEC(i+1); ik++)
|
||||
{
|
||||
const auto ak = uEE(ik);
|
||||
const size_t patch_k = P[e2f(ak)];
|
||||
if (patch_adj[patch_j].find(patch_k) == patch_adj[patch_j].end())
|
||||
{
|
||||
patch_adj[patch_j].insert({patch_k, i});
|
||||
}
|
||||
if (patch_adj[patch_k].find(patch_j) == patch_adj[patch_k].end())
|
||||
{
|
||||
patch_adj[patch_k].insert({patch_j, i});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
log_time("patch-adjacency");
|
||||
|
||||
|
||||
const int INVALID = std::numeric_limits<int>::max();
|
||||
//std::vector<size_t> cell_labels(num_patches * 2);
|
||||
//for (size_t i=0; i<num_patches; i++) cell_labels[i] = i;
|
||||
std::vector<std::set<size_t> > equivalent_cells(num_patches*2);
|
||||
std::vector<bool> processed(num_unique_edges, false);
|
||||
|
||||
size_t label_count=0;
|
||||
size_t order_facets_around_edge_calls = 0;
|
||||
// bottleneck appears to be `order_facets_around_edge`
|
||||
for (size_t i=0; i<num_patches; i++)
|
||||
{
|
||||
for (const auto& entry : patch_adj[i])
|
||||
{
|
||||
const size_t neighbor_patch = entry.first;
|
||||
const size_t uei = entry.second;
|
||||
if (processed[uei]) continue;
|
||||
processed[uei] = true;
|
||||
|
||||
//const auto& adj_faces = uE2E[uei];
|
||||
//const size_t num_adj_faces = adj_faces.size();
|
||||
const size_t num_adj_faces = uEC(uei+1)-uEC(uei);
|
||||
assert(num_adj_faces > 2);
|
||||
|
||||
const size_t s = uE(uei,0);
|
||||
const size_t d = uE(uei,1);
|
||||
|
||||
std::vector<int> signed_adj_faces;
|
||||
//for (auto ej : adj_faces)
|
||||
for(size_t ij = uEC(uei);ij<uEC(uei+1);ij++)
|
||||
{
|
||||
const size_t ej = uEE(ij);
|
||||
const size_t fid = e2f(ej);
|
||||
bool cons = is_consistent(fid, s, d);
|
||||
signed_adj_faces.push_back((fid+1)*(cons ? 1:-1));
|
||||
}
|
||||
{
|
||||
// Sort adjacent faces cyclically around {s,d}
|
||||
Eigen::VectorXi order;
|
||||
// order[f] will reveal the order of face f in signed_adj_faces
|
||||
order_facets_around_edge(V, F, s, d, signed_adj_faces, order);
|
||||
order_facets_around_edge_calls++;
|
||||
for (size_t j=0; j<num_adj_faces; j++)
|
||||
{
|
||||
const size_t curr_idx = j;
|
||||
const size_t next_idx = (j+1)%num_adj_faces;
|
||||
//const size_t curr_patch_idx = P[e2f(adj_faces[order[curr_idx]])];
|
||||
//const size_t next_patch_idx = P[e2f(adj_faces[order[next_idx]])];
|
||||
const size_t curr_patch_idx = P[e2f( uEE(uEC(uei)+order[curr_idx]) )];
|
||||
const size_t next_patch_idx = P[e2f( uEE(uEC(uei)+order[next_idx]) )];
|
||||
const bool curr_cons = signed_adj_faces[order[curr_idx]] > 0;
|
||||
const bool next_cons = signed_adj_faces[order[next_idx]] > 0;
|
||||
const size_t curr_cell_idx = curr_patch_idx*2 + (curr_cons?0:1);
|
||||
const size_t next_cell_idx = next_patch_idx*2 + (next_cons?1:0);
|
||||
equivalent_cells[curr_cell_idx].insert(next_cell_idx);
|
||||
equivalent_cells[next_cell_idx].insert(curr_cell_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef EXTRACT_CELLS_SINGLE_COMPONENT_TIMING
|
||||
log_time("equivalent_cells");
|
||||
#endif
|
||||
|
||||
size_t count=0;
|
||||
cells.resize(num_patches, 2);
|
||||
cells.setConstant(INVALID);
|
||||
const auto extract_equivalent_cells = [&](size_t i) {
|
||||
if (cells(i/2, i%2) != INVALID) return;
|
||||
std::queue<size_t> Q;
|
||||
Q.push(i);
|
||||
cells(i/2, i%2) = count;
|
||||
while (!Q.empty()) {
|
||||
const size_t index = Q.front();
|
||||
Q.pop();
|
||||
for (const auto j : equivalent_cells[index]) {
|
||||
if (cells(j/2, j%2) == INVALID) {
|
||||
cells(j/2, j%2) = count;
|
||||
Q.push(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
count++;
|
||||
};
|
||||
for (size_t i=0; i<num_patches; i++) {
|
||||
extract_equivalent_cells(i*2);
|
||||
extract_equivalent_cells(i*2+1);
|
||||
}
|
||||
log_time("extract-equivalent_cells");
|
||||
|
||||
assert((cells.array() != INVALID).all());
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template size_t igl::copyleft::cgal::extract_cells_single_component<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -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<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
#include <cstdint>
|
||||
template size_t igl::copyleft::cgal::extract_cells_single_component<Eigen::Matrix<CGAL::Epeck::FT, -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<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
#ifdef WIN32
|
||||
template uint64_t igl::copyleft::cgal::extract_cells_single_component<Eigen::Matrix<CGAL::Epeck::FT, -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<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,63 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@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_COPYLEFT_CGAL_EXTRACT_CELLS_SINGLE_COMPONENT_H
|
||||
#define IGL_COPYLEFT_CGAL_EXTRACT_CELLS_SINGLE_COMPONENT_H
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
|
||||
namespace igl {
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
/// Extract connected 3D space partitioned by mesh (V,F) composed of
|
||||
/// **possibly multiple components** (the name of this function is
|
||||
/// dubious).
|
||||
///
|
||||
/// @param[in] V #V by 3 array of vertices.
|
||||
/// @param[in] F #F by 3 array of faces.
|
||||
/// @param[in] P #F list of patch indices.
|
||||
/// @param[in] E #E by 2 array of vertex indices, one edge per row.
|
||||
/// @param[in] uE #uE by 2 list of vertex_indices, represents undirected edges.
|
||||
/// @param[in] EMAP #F*3 list of indices into uE.
|
||||
/// @param[in] uEC #uE+1 list of cumsums of directed edges sharing each unique edge
|
||||
/// @param[in] uEE #E list of indices into E (see `igl::unique_edge_map`)
|
||||
/// @param[out] cells #P by 2 array of cell indices. cells(i,0) represents the
|
||||
/// cell index on the positive side of patch i, and cells(i,1)
|
||||
/// represents cell index of the negative side.
|
||||
/// @return number of components
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename DeriveduE,
|
||||
typename DerivedEMAP,
|
||||
typename DeriveduEC,
|
||||
typename DeriveduEE,
|
||||
typename DerivedC >
|
||||
IGL_INLINE size_t extract_cells_single_component(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
const Eigen::PlainObjectBase<DeriveduEC>& uEC,
|
||||
const Eigen::PlainObjectBase<DeriveduEE>& uEE,
|
||||
Eigen::PlainObjectBase<DerivedC>& cells);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "extract_cells_single_component.cpp"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Qingnan Zhou <qnzhou@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 "extract_feature.h"
|
||||
#include "../../unique_edge_map.h"
|
||||
#include "../../PI.h"
|
||||
#include <CGAL/Kernel/global_functions.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedE >
|
||||
IGL_INLINE void igl::copyleft::cgal::extract_feature(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const double tol,
|
||||
Eigen::PlainObjectBase<DerivedE>& feature_edges) {
|
||||
|
||||
using IndexType = typename DerivedE::Scalar;
|
||||
DerivedE E, uE;
|
||||
Eigen::VectorXi EMAP;
|
||||
std::vector<std::vector<IndexType> > uE2E;
|
||||
igl::unique_edge_map(F, E, uE, EMAP, uE2E);
|
||||
|
||||
igl::copyleft::cgal::extract_feature(V, F, tol, E, uE, uE2E, feature_edges);
|
||||
}
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedE >
|
||||
IGL_INLINE void igl::copyleft::cgal::extract_feature(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const double tol,
|
||||
const Eigen::PlainObjectBase<DerivedE>& E,
|
||||
const Eigen::PlainObjectBase<DerivedE>& uE,
|
||||
const std::vector<std::vector<typename DerivedE::Scalar> >& uE2E,
|
||||
Eigen::PlainObjectBase<DerivedE>& feature_edges) {
|
||||
|
||||
assert(V.cols() == 3);
|
||||
assert(F.cols() == 3);
|
||||
using Scalar = typename DerivedV::Scalar;
|
||||
using IndexType = typename DerivedE::Scalar;
|
||||
using Vertex = Eigen::Matrix<Scalar, 3, 1>;
|
||||
using Kernel = typename CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
using Point = typename Kernel::Point_3;
|
||||
|
||||
const size_t num_unique_edges = uE.rows();
|
||||
const size_t num_faces = F.rows();
|
||||
// NOTE: CGAL's definition of dihedral angle measures the angle between two
|
||||
// facets instead of facet normals.
|
||||
const double cos_tol = cos(igl::PI - tol);
|
||||
std::vector<size_t> result; // Indices into uE
|
||||
|
||||
auto is_non_manifold = [&uE2E](size_t ei) -> bool {
|
||||
return uE2E[ei].size() > 2;
|
||||
};
|
||||
|
||||
auto is_boundary = [&uE2E](size_t ei) -> bool {
|
||||
return uE2E[ei].size() == 1;
|
||||
};
|
||||
|
||||
auto opposite_vertex = [&uE, &F](size_t ei, size_t fi) -> IndexType {
|
||||
const size_t v0 = uE(ei, 0);
|
||||
const size_t v1 = uE(ei, 1);
|
||||
for (size_t i=0; i<3; i++) {
|
||||
const size_t v = F(fi, i);
|
||||
if (v != v0 && v != v1) { return v; }
|
||||
}
|
||||
throw "Input face must be topologically degenerate!";
|
||||
};
|
||||
|
||||
auto is_feature = [&V, &F, &uE, &uE2E, &opposite_vertex, num_faces](
|
||||
size_t ei, double cos_tol) -> bool {
|
||||
auto adj_faces = uE2E[ei];
|
||||
assert(adj_faces.size() == 2);
|
||||
const Vertex v0 = V.row(uE(ei, 0));
|
||||
const Vertex v1 = V.row(uE(ei, 1));
|
||||
const Vertex v2 = V.row(opposite_vertex(ei, adj_faces[0] % num_faces));
|
||||
const Vertex v3 = V.row(opposite_vertex(ei, adj_faces[1] % num_faces));
|
||||
const Point p0(v0[0], v0[1], v0[2]);
|
||||
const Point p1(v1[0], v1[1], v1[2]);
|
||||
const Point p2(v2[0], v2[1], v2[2]);
|
||||
const Point p3(v3[0], v3[1], v3[2]);
|
||||
const auto ori = CGAL::orientation(p0, p1, p2, p3);
|
||||
switch (ori) {
|
||||
case CGAL::POSITIVE:
|
||||
return CGAL::compare_dihedral_angle(p0, p1, p2, p3, cos_tol) ==
|
||||
CGAL::SMALLER;
|
||||
case CGAL::NEGATIVE:
|
||||
return CGAL::compare_dihedral_angle(p0, p1, p3, p2, cos_tol) ==
|
||||
CGAL::SMALLER;
|
||||
case CGAL::COPLANAR:
|
||||
if (!CGAL::collinear(p0, p1, p2) && !CGAL::collinear(p0, p1, p3)) {
|
||||
return CGAL::compare_dihedral_angle(p0, p1, p2, p3, cos_tol) ==
|
||||
CGAL::SMALLER;
|
||||
} else {
|
||||
throw "Dihedral angle (and feature edge) is not well defined for"
|
||||
" degenerate triangles!";
|
||||
}
|
||||
default:
|
||||
throw "Unknown CGAL orientation";
|
||||
}
|
||||
};
|
||||
|
||||
for (size_t i=0; i<num_unique_edges; i++) {
|
||||
if (is_boundary(i) || is_non_manifold(i) || is_feature(i, cos_tol)) {
|
||||
result.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
const size_t num_feature_edges = result.size();
|
||||
feature_edges.resize(num_feature_edges, 2);
|
||||
for (size_t i=0; i<num_feature_edges; i++) {
|
||||
feature_edges.row(i) = uE.row(result[i]);
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Qingnan Zhou <qnzhou@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_COPYLEFT_CGAL_EXTRACT_FEATURE_H
|
||||
#define IGL_COPYLEFT_CGAL_EXTRACT_FEATURE_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
/// Extract feature edges based on dihedral angle.
|
||||
/// Here, dihedral angle is defined as the angle between surface
|
||||
/// __normals__ as described in
|
||||
/// http://mathworld.wolfram.com/DihedralAngle.html
|
||||
///
|
||||
/// Non-manifold and boundary edges are automatically considered as
|
||||
/// features.
|
||||
///
|
||||
/// @param[in] V #V by 3 array of vertices.
|
||||
/// @param[in] F #F by 3 array of faces.
|
||||
/// @param[in] tol Edges with dihedral angle larger than this are considered
|
||||
/// as features. Angle is measured in radian.
|
||||
/// @param[out] feature_edges: #E by 2 array of edges. Each edge satisfies at
|
||||
/// least one of the following criteria:
|
||||
/// * Edge has dihedral angle larger than tol.
|
||||
/// * Edge is boundary.
|
||||
/// * Edge is non-manifold (i.e. it has more than 2 adjacent
|
||||
/// faces).
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedE>
|
||||
IGL_INLINE void extract_feature(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const double tol,
|
||||
Eigen::PlainObjectBase<DerivedE>& feature_edges);
|
||||
// \overload
|
||||
// @param[in] E #E by 2 array of directed edges.
|
||||
// @param[in] uE #uE by 2 array of undirected edges.
|
||||
// @param[in] uE2E #uE list of lists mapping undirected edges to all
|
||||
// corresponding directed edges.
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedE>
|
||||
IGL_INLINE void extract_feature(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const double tol,
|
||||
const Eigen::PlainObjectBase<DerivedE>& E,
|
||||
const Eigen::PlainObjectBase<DerivedE>& uE,
|
||||
const std::vector<std::vector<typename DerivedE::Scalar> >& uE2E,
|
||||
Eigen::PlainObjectBase<DerivedE>& feature_edges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "extract_feature.cpp"
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,65 +0,0 @@
|
||||
#include "fast_winding_number.h"
|
||||
#include "../../fast_winding_number.h"
|
||||
#include "../../octree.h"
|
||||
#include "../../knn.h"
|
||||
#include "../../parallel_for.h"
|
||||
#include "point_areas.h"
|
||||
#include <vector>
|
||||
|
||||
template <
|
||||
typename DerivedP,
|
||||
typename DerivedN,
|
||||
typename DerivedQ,
|
||||
typename BetaType,
|
||||
typename DerivedWN>
|
||||
IGL_INLINE void igl::copyleft::cgal::fast_winding_number(
|
||||
const Eigen::MatrixBase<DerivedP>& P,
|
||||
const Eigen::MatrixBase<DerivedN>& N,
|
||||
const Eigen::MatrixBase<DerivedQ>& Q,
|
||||
const int expansion_order,
|
||||
const BetaType beta,
|
||||
Eigen::PlainObjectBase<DerivedWN>& WN)
|
||||
{
|
||||
typedef typename DerivedWN::Scalar real;
|
||||
typedef typename Eigen::Matrix<real,Eigen::Dynamic,Eigen::Dynamic>
|
||||
RealMatrix;
|
||||
|
||||
std::vector<std::vector<int> > point_indices;
|
||||
Eigen::Matrix<int,Eigen::Dynamic,8> CH;
|
||||
Eigen::Matrix<real,Eigen::Dynamic,3> CN;
|
||||
Eigen::Matrix<real,Eigen::Dynamic,1> W;
|
||||
Eigen::MatrixXi I;
|
||||
Eigen::Matrix<real,Eigen::Dynamic,1> A;
|
||||
|
||||
octree(P,point_indices,CH,CN,W);
|
||||
knn(P,21,point_indices,CH,CN,W,I);
|
||||
point_areas(P,I,N,A);
|
||||
|
||||
Eigen::Matrix<real,Eigen::Dynamic,Eigen::Dynamic> EC;
|
||||
Eigen::Matrix<real,Eigen::Dynamic,3> CM;
|
||||
Eigen::Matrix<real,Eigen::Dynamic,1> R;
|
||||
|
||||
igl::fast_winding_number(
|
||||
P,N,A,point_indices,CH,expansion_order,CM,R,EC);
|
||||
igl::fast_winding_number(
|
||||
P,N,A,point_indices,CH,CM,R,EC,Q,beta,WN);
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedP,
|
||||
typename DerivedN,
|
||||
typename DerivedQ,
|
||||
typename DerivedWN>
|
||||
IGL_INLINE void igl::copyleft::cgal::fast_winding_number(
|
||||
const Eigen::MatrixBase<DerivedP>& P,
|
||||
const Eigen::MatrixBase<DerivedN>& N,
|
||||
const Eigen::MatrixBase<DerivedQ>& Q,
|
||||
Eigen::PlainObjectBase<DerivedWN>& WN)
|
||||
{
|
||||
fast_winding_number(P,N,Q,2,2.0,WN);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::copyleft::cgal::fast_winding_number<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -1,61 +0,0 @@
|
||||
#ifndef IGL_COPYLEFT_CGAL_FAST_WINDING_NUMBER
|
||||
#define IGL_COPYLEFT_CGAL_FAST_WINDING_NUMBER
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
/// Evaluate the fast winding number for point data, without known areas. The
|
||||
/// areas are calculated using igl::knn and igl::copyleft::cgal::point_areas.
|
||||
///
|
||||
/// This function performes the precomputation and evaluation all in one.
|
||||
/// If you need to acess the precomuptation for repeated evaluations, use the
|
||||
/// two functions designed for exposed precomputation, which are the first two
|
||||
/// functions see in igl/fast_winding_number.h
|
||||
///
|
||||
/// @param[in] P #P by 3 list of point locations
|
||||
/// @param[in] N #P by 3 list of point normals
|
||||
/// @param[in] Q #Q by 3 list of query points for the winding number
|
||||
/// @param[in] beta This is a Barnes-Hut style accuracy term that separates near feild
|
||||
/// from far field. The higher the beta, the more accurate and slower
|
||||
/// the evaluation. We reccommend using a beta value of 2.
|
||||
/// @param[in] expansion_order the order of the taylor expansion. We support 0,1,2.
|
||||
/// @param[out] WN #Q by 1 list of windinng number values at each query point
|
||||
///
|
||||
template <
|
||||
typename DerivedP,
|
||||
typename DerivedN,
|
||||
typename DerivedQ,
|
||||
typename BetaType,
|
||||
typename DerivedWN>
|
||||
IGL_INLINE void fast_winding_number(
|
||||
const Eigen::MatrixBase<DerivedP>& P,
|
||||
const Eigen::MatrixBase<DerivedN>& N,
|
||||
const Eigen::MatrixBase<DerivedQ>& Q,
|
||||
const int expansion_order,
|
||||
const BetaType beta,
|
||||
Eigen::PlainObjectBase<DerivedWN>& WN);
|
||||
/// \overload
|
||||
template <
|
||||
typename DerivedP,
|
||||
typename DerivedN,
|
||||
typename DerivedQ,
|
||||
typename DerivedWN>
|
||||
IGL_INLINE void fast_winding_number(
|
||||
const Eigen::MatrixBase<DerivedP>& P,
|
||||
const Eigen::MatrixBase<DerivedN>& N,
|
||||
const Eigen::MatrixBase<DerivedQ>& Q,
|
||||
Eigen::PlainObjectBase<DerivedWN>& WN);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "fast_winding_number.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
#include "half_space_box.h"
|
||||
#include "assign_scalar.h"
|
||||
#include <CGAL/Point_3.h>
|
||||
#include <CGAL/Vector_3.h>
|
||||
|
||||
template <typename DerivedV>
|
||||
IGL_INLINE void igl::copyleft::cgal::half_space_box(
|
||||
const CGAL::Plane_3<CGAL::Epeck> & P,
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::Matrix<CGAL::Epeck::FT,8,3> & BV,
|
||||
Eigen::Matrix<int,12,3> & BF)
|
||||
{
|
||||
typedef CGAL::Plane_3<CGAL::Epeck> Plane;
|
||||
typedef CGAL::Point_3<CGAL::Epeck> Point;
|
||||
typedef CGAL::Vector_3<CGAL::Epeck> Vector;
|
||||
typedef CGAL::Epeck::FT EScalar;
|
||||
Eigen::Matrix<typename DerivedV::Scalar,1,3> avg(0,0,0);
|
||||
for(int v = 0;v<V.rows();v++) for(int c = 0;c<V.cols();c++) avg(c) += V(v,c);
|
||||
avg /= V.rows();
|
||||
|
||||
Point o3(avg(0),avg(1),avg(2));
|
||||
Point o2 = P.projection(o3);
|
||||
Vector u;
|
||||
EScalar max_sqrd = -1;
|
||||
for(int v = 0;v<V.rows();v++)
|
||||
{
|
||||
Vector v2 = P.projection(Point(V(v,0),V(v,1),V(v,2))) - o2;
|
||||
const EScalar sqrd = v2.squared_length();
|
||||
if(max_sqrd<0 || sqrd < max_sqrd)
|
||||
{
|
||||
u = v2;
|
||||
max_sqrd = sqrd;
|
||||
}
|
||||
}
|
||||
// L1 bbd
|
||||
const EScalar bbd =
|
||||
(EScalar(V.col(0).maxCoeff())- EScalar(V.col(0).minCoeff())) +
|
||||
(EScalar(V.col(1).maxCoeff())- EScalar(V.col(1).minCoeff())) +
|
||||
(EScalar(V.col(2).maxCoeff())- EScalar(V.col(2).minCoeff()));
|
||||
Vector n = P.orthogonal_vector();
|
||||
// now we have a center o2 and a vector u to the farthest point on the plane
|
||||
std::vector<Point> vBV;vBV.reserve(8);
|
||||
Vector v = CGAL::cross_product(u,n);
|
||||
// Scale u,v,n to be longer than bbd
|
||||
const auto & longer_than = [](const EScalar min_sqr, Vector & x)
|
||||
{
|
||||
assert(x.squared_length() > 0);
|
||||
while(x.squared_length() < min_sqr)
|
||||
{
|
||||
x = 2.*x;
|
||||
}
|
||||
};
|
||||
longer_than(bbd*bbd,u);
|
||||
longer_than(bbd*bbd,v);
|
||||
longer_than(bbd*bbd,n);
|
||||
vBV.emplace_back( o2 + u + v);
|
||||
vBV.emplace_back( o2 - u + v);
|
||||
vBV.emplace_back( o2 - u - v);
|
||||
vBV.emplace_back( o2 + u - v);
|
||||
vBV.emplace_back( o2 + u + v - n);
|
||||
vBV.emplace_back( o2 - u + v - n);
|
||||
vBV.emplace_back( o2 - u - v - n);
|
||||
vBV.emplace_back( o2 + u - v - n);
|
||||
BV.resize(8,3);
|
||||
for(int b = 0;b<8;b++)
|
||||
{
|
||||
igl::copyleft::cgal::assign_scalar(vBV[b].x(),BV(b,0));
|
||||
igl::copyleft::cgal::assign_scalar(vBV[b].y(),BV(b,1));
|
||||
igl::copyleft::cgal::assign_scalar(vBV[b].z(),BV(b,2));
|
||||
}
|
||||
BF.resize(12,3);
|
||||
BF<<
|
||||
1,0,2,
|
||||
2,0,3,
|
||||
4,5,6,
|
||||
4,6,7,
|
||||
0,1,4,
|
||||
4,1,5,
|
||||
1,2,5,
|
||||
5,2,6,
|
||||
2,3,6,
|
||||
6,3,7,
|
||||
3,0,7,
|
||||
7,0,4;
|
||||
}
|
||||
|
||||
template <typename Derivedp, typename Derivedn, typename DerivedV>
|
||||
IGL_INLINE void igl::copyleft::cgal::half_space_box(
|
||||
const Eigen::MatrixBase<Derivedp> & p,
|
||||
const Eigen::MatrixBase<Derivedn> & n,
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::Matrix<CGAL::Epeck::FT,8,3> & BV,
|
||||
Eigen::Matrix<int,12,3> & BF)
|
||||
{
|
||||
typedef CGAL::Plane_3<CGAL::Epeck> Plane;
|
||||
typedef CGAL::Point_3<CGAL::Epeck> Point;
|
||||
typedef CGAL::Vector_3<CGAL::Epeck> Vector;
|
||||
Plane P(Point(p(0),p(1),p(2)),Vector(n(0),n(1),n(2)));
|
||||
return half_space_box(P,V,BV,BF);
|
||||
}
|
||||
|
||||
template <typename Derivedequ, typename DerivedV>
|
||||
IGL_INLINE void igl::copyleft::cgal::half_space_box(
|
||||
const Eigen::MatrixBase<Derivedequ> & equ,
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::Matrix<CGAL::Epeck::FT,8,3> & BV,
|
||||
Eigen::Matrix<int,12,3> & BF)
|
||||
{
|
||||
typedef CGAL::Plane_3<CGAL::Epeck> Plane;
|
||||
Plane P(equ(0),equ(1),equ(2),equ(3));
|
||||
return half_space_box(P,V,BV,BF);
|
||||
}
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::copyleft::cgal::half_space_box<Eigen::Matrix<double, -1, 3, 1, -1, 3> >(CGAL::Plane_3<CGAL::Epeck> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<CGAL::Epeck::FT, 8, 3, 0, 8, 3>&, Eigen::Matrix<int, 12, 3, 0, 12, 3>&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::half_space_box<Eigen::Matrix<float, -1, 3, 1, -1, 3> >(CGAL::Plane_3<CGAL::Epeck> const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<CGAL::Epeck::FT, 8, 3, 0, 8, 3>&, Eigen::Matrix<int, 12, 3, 0, 12, 3>&);
|
||||
template void igl::copyleft::cgal::half_space_box<Eigen::Matrix<CGAL::Epeck::FT, 1, 4, 1, 1, 4>, Eigen::Matrix<CGAL::Epeck::FT, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, 1, 4, 1, 1, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, -1, 3, 0, -1, 3> > const&, Eigen::Matrix<CGAL::Epeck::FT, 8, 3, 0, 8, 3>&, Eigen::Matrix<int, 12, 3, 0, 12, 3>&);
|
||||
template void igl::copyleft::cgal::half_space_box<Eigen::Matrix<CGAL::Epeck::FT, 1, 4, 1, 1, 4>, Eigen::Matrix<CGAL::Epeck::FT, -1, 4, 0, -1, 4> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, 1, 4, 1, 1, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, -1, 4, 0, -1, 4> > const&, Eigen::Matrix<CGAL::Epeck::FT, 8, 3, 0, 8, 3>&, Eigen::Matrix<int, 12, 3, 0, 12, 3>&);
|
||||
template void igl::copyleft::cgal::half_space_box<Eigen::Matrix<CGAL::Epeck::FT, 1, 4, 1, 1, 4>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, 1, 4, 1, 1, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<CGAL::Epeck::FT, 8, 3, 0, 8, 3>&, Eigen::Matrix<int, 12, 3, 0, 12, 3>&);
|
||||
template void igl::copyleft::cgal::half_space_box<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<CGAL::Epeck::FT, 8, 3, 0, 8, 3>&, Eigen::Matrix<int, 12, 3, 0, 12, 3>&);
|
||||
#endif
|
||||
@@ -1,53 +0,0 @@
|
||||
#ifndef IGL_COPYLEFT_CGAL_HALF_SPACE_BOX_H
|
||||
#define IGL_COPYLEFT_CGAL_HALF_SPACE_BOX_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Plane_3.h>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
/// Construct a mesh of box (BV,BF) so that it contains the intersection of
|
||||
/// the half-space under the plane (P) and the bounding box of V, and does not
|
||||
/// contain any of the half-space above (P).
|
||||
///
|
||||
/// @param[in] P plane so that normal points away from half-space
|
||||
/// @param[in] V #V by 3 list of vertex positions
|
||||
/// @param[out] BV #BV by 3 list of box vertex positions
|
||||
/// @param[out] BF #BF b3 list of box triangle indices into BV
|
||||
template <typename DerivedV>
|
||||
IGL_INLINE void half_space_box(
|
||||
const CGAL::Plane_3<CGAL::Epeck> & P,
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::Matrix<CGAL::Epeck::FT,8,3> & BV,
|
||||
Eigen::Matrix<int,12,3> & BF);
|
||||
/// \overload
|
||||
/// @param[in] p 3d point on plane
|
||||
/// @param[in] n 3d vector of normal of plane pointing away from inside
|
||||
template <typename Derivedp, typename Derivedn, typename DerivedV>
|
||||
IGL_INLINE void half_space_box(
|
||||
const Eigen::MatrixBase<Derivedp> & p,
|
||||
const Eigen::MatrixBase<Derivedn> & n,
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::Matrix<CGAL::Epeck::FT,8,3> & BV,
|
||||
Eigen::Matrix<int,12,3> & BF);
|
||||
/// \overload
|
||||
/// @param[in] equ plane equation: a*x+b*y+c*z + d = 0
|
||||
template <typename Derivedequ, typename DerivedV>
|
||||
IGL_INLINE void half_space_box(
|
||||
const Eigen::MatrixBase<Derivedequ> & equ,
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::Matrix<CGAL::Epeck::FT,8,3> & BV,
|
||||
Eigen::Matrix<int,12,3> & BF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "half_space_box.cpp"
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,45 +0,0 @@
|
||||
#include "hausdorff.h"
|
||||
#include "../../hausdorff.h"
|
||||
#include <functional>
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename Kernel,
|
||||
typename Scalar>
|
||||
IGL_INLINE void igl::copyleft::cgal::hausdorff(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const CGAL::AABB_tree<
|
||||
CGAL::AABB_traits<Kernel,
|
||||
CGAL::AABB_triangle_primitive<Kernel,
|
||||
typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
|
||||
>
|
||||
>
|
||||
> & treeB,
|
||||
const std::vector<CGAL::Triangle_3<Kernel> > & /*TB*/,
|
||||
Scalar & l,
|
||||
Scalar & u)
|
||||
{
|
||||
// Not sure why using `auto` here doesn't work with the `hausdorff` function
|
||||
// parameter but explicitly naming the type does...
|
||||
const std::function<double(const double &,const double &,const double &)>
|
||||
dist_to_B = [&treeB](
|
||||
const double & x, const double & y, const double & z)->double
|
||||
{
|
||||
CGAL::Point_3<Kernel> query(x,y,z);
|
||||
typename CGAL::AABB_tree<
|
||||
CGAL::AABB_traits<Kernel,
|
||||
CGAL::AABB_triangle_primitive<Kernel,
|
||||
typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
|
||||
>
|
||||
>
|
||||
>::Point_and_primitive_id pp = treeB.closest_point_and_primitive(query);
|
||||
return std::sqrt((query-pp.first).squared_length());
|
||||
};
|
||||
return igl::hausdorff(V,dist_to_B,l,u);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::hausdorff<Eigen::Matrix<double, -1, -1, 0, -1, -1>, CGAL::Simple_cartesian<double>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, CGAL::AABB_tree<CGAL::AABB_traits<CGAL::Simple_cartesian<double>, CGAL::AABB_triangle_primitive<CGAL::Simple_cartesian<double>, std::vector<CGAL::Triangle_3<CGAL::Simple_cartesian<double> >, std::allocator<CGAL::Triangle_3<CGAL::Simple_cartesian<double> > > >::iterator, CGAL::Boolean_tag<false> >, CGAL::Default> > const&, std::vector<CGAL::Triangle_3<CGAL::Simple_cartesian<double> >, std::allocator<CGAL::Triangle_3<CGAL::Simple_cartesian<double> > > > const&, double&, double&);
|
||||
#endif
|
||||
@@ -1,60 +0,0 @@
|
||||
// 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_COPYLEFT_CGAL_HAUSDORFF_H
|
||||
#define IGL_COPYLEFT_CGAL_HAUSDORFF_H
|
||||
#include "../../igl_inline.h"
|
||||
|
||||
#include <Eigen/Dense>
|
||||
#include "CGAL_includes.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
/// Compute lower and upper bounds (l,u) on the Hausdorff distance between a triangle
|
||||
/// (V) and a pointset (e.g., mesh, triangle soup) given by a distance function
|
||||
/// handle (dist_to_B).
|
||||
///
|
||||
/// @param[in] V 3 by 3 list of corner positions so that V.row(i) is the position of the
|
||||
/// ith corner
|
||||
/// @param[in] treeB CGAL's AABB tree containing triangle soup (VB,FB)
|
||||
/// @param[in] TB list of CGAL triangles in order of FB (for determining which was found
|
||||
/// in computation)
|
||||
/// @param[out] l lower bound on Hausdorff distance
|
||||
/// @param[out] u upper bound on Hausdorff distance
|
||||
///
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename Kernel,
|
||||
typename Scalar>
|
||||
IGL_INLINE void hausdorff(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const CGAL::AABB_tree<
|
||||
CGAL::AABB_traits<Kernel,
|
||||
CGAL::AABB_triangle_primitive<Kernel,
|
||||
typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
|
||||
>
|
||||
>
|
||||
> & treeB,
|
||||
const std::vector<CGAL::Triangle_3<Kernel> > & TB,
|
||||
Scalar & l,
|
||||
Scalar & u);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "hausdorff.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Qingan Zhou <qnzhou@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 "incircle.h"
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
template<typename Scalar>
|
||||
IGL_INLINE short igl::copyleft::cgal::incircle(
|
||||
const Scalar *pa,
|
||||
const Scalar *pb,
|
||||
const Scalar *pc,
|
||||
const Scalar *pd)
|
||||
{
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Epeck;
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Epick;
|
||||
typedef typename std::conditional<std::is_same<Scalar, Epeck::FT>::value,
|
||||
Epeck, Epick>::type Kernel;
|
||||
|
||||
switch(CGAL::side_of_oriented_circle(
|
||||
typename Kernel::Point_2(pa[0], pa[1]),
|
||||
typename Kernel::Point_2(pb[0], pb[1]),
|
||||
typename Kernel::Point_2(pc[0], pc[1]),
|
||||
typename Kernel::Point_2(pd[0], pd[1]))) {
|
||||
case CGAL::ON_POSITIVE_SIDE:
|
||||
return 1;
|
||||
case CGAL::ON_NEGATIVE_SIDE:
|
||||
return -1;
|
||||
case CGAL::ON_ORIENTED_BOUNDARY:
|
||||
return 0;
|
||||
default:
|
||||
throw "Invalid incircle result";
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template short igl::copyleft::cgal::incircle<double>(double const*, double const*, double const*, double const*);
|
||||
#ifdef WIN32
|
||||
template short igl::copyleft::cgal::incircle<double>(double const * const,double const * const,double const * const,double const * const);
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,42 +0,0 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Qingan Zhou <qnzhou@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_COPYLEFT_CGAL_INCIRCLE_H
|
||||
#define IGL_COPYLEFT_CGAL_INCIRCLE_H
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
/// Test whether point is in a given circle
|
||||
///
|
||||
/// @param[in] pa 2D point on sphere
|
||||
/// @param[in] pb 2D point on sphere
|
||||
/// @param[in] pc 2D point on sphere
|
||||
/// @param[in] pd 2D point to test
|
||||
/// @return 1 if pd is inside of the oriented circle formed by pa,pb,pc.
|
||||
/// 0 if pd is co-circular with pa,pb,pc.
|
||||
/// -1 if pd is outside of the oriented circle formed by pa,pb,pc.
|
||||
template <typename Scalar>
|
||||
IGL_INLINE short incircle(
|
||||
const Scalar *pa,
|
||||
const Scalar *pb,
|
||||
const Scalar *pc,
|
||||
const Scalar *pd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "incircle.cpp"
|
||||
#endif
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user