Compare commits

...
Author SHA1 Message Date
Alec Jacobson e3283e29b7 delete everything but 101 2023-08-24 17:23:27 -04:00
Alec Jacobson 261fec1d05 blah 2023-08-24 17:16:39 -04:00
Alec Jacobson ab6229c77a Euler Characteristic tests (#2250)
* test for euler characteristic

* doc
2023-08-23 16:19:42 -04:00
Alec Jacobson b1fe6ba49c read blank lines as comments (#2247) [ci skip] 2023-08-22 20:20:53 -04:00
Alec Jacobson 8d940367bf support rowmajor (#2246) [ci skip] 2023-08-22 20:20:34 -04:00
744 changed files with 115 additions and 97190 deletions
-49
View File
@@ -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()
-19
View File
@@ -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)
-1074
View File
File diff suppressed because it is too large Load Diff
-130
View File
@@ -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
-30
View File
@@ -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
-162
View File
@@ -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
-497
View File
@@ -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));
}
}
-347
View File
@@ -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();
}
-52
View File
@@ -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
-370
View File
@@ -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
-180
View File
@@ -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
-125
View File
@@ -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
-26
View File
@@ -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
-39
View File
@@ -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
-139
View File
@@ -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
-20
View File
@@ -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);
}
-26
View File
@@ -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
-306
View File
@@ -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
-883
View File
@@ -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
-259
View File
@@ -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
-95
View File
@@ -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
-27
View File
@@ -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
-33
View File
@@ -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
-39
View File
@@ -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
-42
View File
@@ -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
-58
View File
@@ -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
-113
View File
@@ -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
-42
View File
@@ -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
-38
View File
@@ -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());
}
-144
View File
@@ -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
-74
View File
@@ -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
-93
View File
@@ -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});
}
}
}
-100
View File
@@ -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
-207
View File
@@ -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
-71
View File
@@ -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
-379
View File
@@ -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
-32
View File
@@ -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
-245
View File
@@ -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;
}
-225
View File
@@ -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
-154
View File
@@ -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
-105
View File
@@ -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
-26
View File
@@ -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
-21
View File
@@ -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
-263
View File
@@ -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
-24
View File
@@ -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
-73
View File
@@ -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
-143
View File
@@ -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;
}
}
}
-30
View File
@@ -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
-373
View File
@@ -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;
}
-139
View File
@@ -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);
}
-69
View File
@@ -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
-27
View File
@@ -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;
}
-63
View File
@@ -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
-155
View File
@@ -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
-78
View File
@@ -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
-132
View File
@@ -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
-99
View File
@@ -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
-63
View File
@@ -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
-187
View File
@@ -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
-88
View File
@@ -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
-56
View File
@@ -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
-199
View File
@@ -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
-109
View File
@@ -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
-16
View File
@@ -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
-509
View File
@@ -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
-158
View File
@@ -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
-103
View File
@@ -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
-47
View File
@@ -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
-48
View File
@@ -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
-25
View File
@@ -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
-397
View File
@@ -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
-72
View File
@@ -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
-45
View File
@@ -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
-60
View File
@@ -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
-48
View File
@@ -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
-42
View File
@@ -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