mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-11-02 20:51:23 -07:00
Merged branch 'dev_native' into lm_sla_supports_auto
Added igl library files
This commit is contained in:
commit
7681d00ee5
2865 changed files with 142806 additions and 22325 deletions
14
src/igl/copyleft/README.md
Normal file
14
src/igl/copyleft/README.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
## IGL copyleft subdirectory
|
||||
|
||||
Functions in the `include/igl/copyleft/` subdirectory are in the
|
||||
`igl::copyleft::` namespace to indicate that they are under a more aggressive
|
||||
[copyleft](https://en.wikipedia.org/wiki/Copyleft) than
|
||||
[MPL2](https://en.wikipedia.org/wiki/Mozilla_Public_License) used for the main
|
||||
`include/igl` directory and `igl::` namespace. Most notably, this subdirectory
|
||||
includes code that is under
|
||||
[GPL](https://en.wikipedia.org/wiki/GNU_General_Public_License).
|
||||
|
||||
Typically a company planning on developing software without releasing its
|
||||
source code will avoid or purchase licenses for such dependencies. If you do
|
||||
obtain such a license for the dependencies employed here, you are free to use
|
||||
the libigl functions here as per their MPL2 license.
|
||||
167
src/igl/copyleft/cgal/BinaryWindingNumberOperations.h
Normal file
167
src/igl/copyleft/cgal/BinaryWindingNumberOperations.h
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
// 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
|
||||
{
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
enum KeeperType {
|
||||
KEEP_INSIDE,
|
||||
KEEP_ALL
|
||||
};
|
||||
|
||||
template<KeeperType T>
|
||||
class WindingNumberFilter {
|
||||
public:
|
||||
template<typename DerivedW>
|
||||
short operator()(
|
||||
const Eigen::PlainObjectBase<DerivedW>& /*win_nums*/) const {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class WindingNumberFilter<KEEP_ALL> {
|
||||
public:
|
||||
template<typename T>
|
||||
short operator()(T /*out_w*/, T /*in_w*/) const {
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
typedef WindingNumberFilter<KEEP_INSIDE> KeepInside;
|
||||
typedef WindingNumberFilter<KEEP_ALL> KeepAll;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
50
src/igl/copyleft/cgal/CGAL_includes.hpp
Normal file
50
src/igl/copyleft/cgal/CGAL_includes.hpp
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
// 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_CGAL_INCLUDES_H
|
||||
#define IGL_CGAL_INCLUDES_H
|
||||
|
||||
// This causes unknown bugs during intersection meshing:
|
||||
//// http://www.alecjacobson.com/weblog/?p=4291
|
||||
//#define CGAL_INTERSECTION_VERSION 1
|
||||
// Use this instead to mute errors resulting from bad CGAL assertions
|
||||
#define CGAL_KERNEL_NO_ASSERTIONS
|
||||
// Triangle triangle intersection
|
||||
#include <CGAL/intersections.h>
|
||||
// THIS CANNOT BE INCLUDED IN THE SAME FILE AS <CGAL/intersections.h>
|
||||
// #include <CGAL/Boolean_set_operations_2.h>
|
||||
|
||||
// Constrained Delaunay Triangulation types
|
||||
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
|
||||
#include <CGAL/Constrained_triangulation_plus_2.h>
|
||||
|
||||
// Axis-align boxes for all-pairs self-intersection detection
|
||||
#include <CGAL/point_generators_3.h>
|
||||
#include <CGAL/Bbox_3.h>
|
||||
#include <CGAL/box_intersection_d.h>
|
||||
#include <CGAL/function_objects.h>
|
||||
#include <CGAL/Join_input_iterator.h>
|
||||
#include <CGAL/algorithm.h>
|
||||
#include <vector>
|
||||
|
||||
// Axis-aligned bounding box tree for tet tri intersection
|
||||
#include <CGAL/AABB_tree.h>
|
||||
#include <CGAL/AABB_traits.h>
|
||||
#include <CGAL/AABB_triangle_primitive.h>
|
||||
|
||||
// Boolean operations
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
// Is this actually used?
|
||||
//#include <CGAL/Nef_polyhedron_3.h>
|
||||
|
||||
// Delaunay Triangulation in 3D
|
||||
#include <CGAL/Delaunay_triangulation_3.h>
|
||||
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#endif
|
||||
189
src/igl/copyleft/cgal/CSGTree.h
Normal file
189
src/igl/copyleft/cgal/CSGTree.h
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
// 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.
|
||||
//
|
||||
//template <typename DerivedF>
|
||||
class CSGTree
|
||||
{
|
||||
public:
|
||||
typedef CGAL::Epeck::FT ExactScalar;
|
||||
//typedef Eigen::PlainObjectBase<DerivedF> POBF;
|
||||
typedef Eigen::MatrixXi POBF;
|
||||
typedef POBF::Index FIndex;
|
||||
typedef Eigen::Matrix<ExactScalar,Eigen::Dynamic,3> MatrixX3E;
|
||||
typedef Eigen::Matrix<FIndex,Eigen::Dynamic,1> VectorJ;
|
||||
private:
|
||||
// Resulting mesh
|
||||
MatrixX3E m_V;
|
||||
POBF m_F;
|
||||
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.
|
||||
//
|
||||
// Inputs:
|
||||
// A Solid result of previous CSG operation (or identity, see below)
|
||||
// B Solid result of previous CSG operation (or identity, see below)
|
||||
// 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 using string for type
|
||||
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)
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of mesh vertices (in any precision, will be
|
||||
// converted to exact)
|
||||
// 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
|
||||
36
src/igl/copyleft/cgal/RemeshSelfIntersectionsParam.h
Normal file
36
src/igl/copyleft/cgal/RemeshSelfIntersectionsParam.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// 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
|
||||
{
|
||||
// Optional Parameters
|
||||
// DetectOnly Only compute IF, leave VV and FF alone
|
||||
struct RemeshSelfIntersectionsParam
|
||||
{
|
||||
bool detect_only;
|
||||
bool first_only;
|
||||
bool stitch_all;
|
||||
inline RemeshSelfIntersectionsParam(
|
||||
bool _detect_only=false,
|
||||
bool _first_only=false,
|
||||
bool _stitch_all=false):
|
||||
detect_only(_detect_only),
|
||||
first_only(_first_only),
|
||||
stitch_all(_stitch_all){};
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
939
src/igl/copyleft/cgal/SelfIntersectMesh.h
Normal file
939
src/igl/copyleft/cgal/SelfIntersectMesh.h
Normal file
|
|
@ -0,0 +1,939 @@
|
|||
// 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 <Eigen/Dense>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
|
||||
//#define IGL_SELFINTERSECTMESH_DEBUG
|
||||
#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
|
||||
{
|
||||
// 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
|
||||
//
|
||||
// See also: 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
|
||||
//
|
||||
// Inputs:
|
||||
// f index of face in F
|
||||
inline void mark_offensive(const Index f);
|
||||
// Helper function to count intersections between faces
|
||||
//
|
||||
// Input:
|
||||
// fa index of face A in F
|
||||
// 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
|
||||
//
|
||||
// Inputs:
|
||||
// A triangle in 3D
|
||||
// B triangle in 3D
|
||||
// fa index of A in F (and key into offending)
|
||||
// fb index of B in F (and key into offending)
|
||||
// Returns 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
|
||||
//
|
||||
// Inputs:
|
||||
// A triangle in 3D
|
||||
// B triangle in 3D
|
||||
// fa index of A in F (and key into offending)
|
||||
// fb index of B in F (and key into offending)
|
||||
// va index of shared vertex in A (and key into offending)
|
||||
// vb index of shared vertex in B (and key into offending)
|
||||
// Returns 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
|
||||
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.
|
||||
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
|
||||
//
|
||||
// Inputs:
|
||||
// a box containing a triangle
|
||||
// b box containing a triangle
|
||||
inline void box_intersect(const Box& a, const Box& b);
|
||||
inline void process_intersecting_boxes();
|
||||
public:
|
||||
// Getters:
|
||||
//const IndexList& get_lIF() const{ return lIF;}
|
||||
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_DEBUG
|
||||
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{
|
||||
std::cout << "SelfIntersectMesh." << label << ": "
|
||||
<< tictoc() << std::endl;
|
||||
};
|
||||
tictoc();
|
||||
#endif
|
||||
|
||||
// Compute and process self intersections
|
||||
mesh_to_cgal_triangle_list(V,F,T);
|
||||
#ifdef IGL_SELFINTERSECTMESH_DEBUG
|
||||
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_DEBUG
|
||||
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_DEBUG
|
||||
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_DEBUG
|
||||
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_DEBUG
|
||||
log_time("store_intersecting_face_pairs");
|
||||
#endif
|
||||
|
||||
if(params.detect_only)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
remesh_intersections(
|
||||
V,F,T,offending,params.stitch_all,VV,FF,J,IM);
|
||||
|
||||
#ifdef IGL_SELFINTERSECTMESH_DEBUG
|
||||
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);
|
||||
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;
|
||||
|
||||
// must be co-planar
|
||||
if(
|
||||
A.supporting_plane() != B.supporting_plane() &&
|
||||
A.supporting_plane() != B.supporting_plane().opposite())
|
||||
{
|
||||
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 a0, const Index a1, const Triangle_3 & B)
|
||||
-> bool
|
||||
{
|
||||
// get opposite index
|
||||
Index a2 = -1;
|
||||
for(int c = 0;c<3;c++)
|
||||
{
|
||||
if(c != a0 && c != a1)
|
||||
{
|
||||
a2 = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(a2 != -1);
|
||||
bool ret = CGAL::do_intersect(A.vertex(a2),B);
|
||||
return ret;
|
||||
};
|
||||
|
||||
// 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,shared[0].first,shared[1].first,B) &&
|
||||
!opposite_point_inside(B,shared[0].second,shared[1].second,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::vector<std::mutex> triangle_locks(T.size());
|
||||
std::vector<std::mutex> vertex_locks(V.rows());
|
||||
std::mutex index_lock;
|
||||
std::mutex exception_mutex;
|
||||
bool exception_fired = false;
|
||||
int exception = -1;
|
||||
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();
|
||||
{
|
||||
// Before knowing which triangles are involved, we need to lock
|
||||
// everything to prevent race condition in updating reference
|
||||
// counters.
|
||||
std::lock_guard<std::mutex> guard(index_lock);
|
||||
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());
|
||||
|
||||
// Lock triangles
|
||||
std::lock_guard<std::mutex> guard_A(triangle_locks[fa]);
|
||||
std::lock_guard<std::mutex> guard_B(triangle_locks[fb]);
|
||||
|
||||
// Lock vertices
|
||||
std::list<std::lock_guard<std::mutex> > guard_vertices;
|
||||
{
|
||||
std::vector<typename DerivedF::Scalar> unique_vertices;
|
||||
std::vector<size_t> tmp1, tmp2;
|
||||
igl::unique({F(fa,0), F(fa,1), F(fa,2), F(fb,0), F(fb,1), F(fb,2)},
|
||||
unique_vertices, tmp1, tmp2);
|
||||
std::for_each(unique_vertices.begin(), unique_vertices.end(),
|
||||
[&](const typename DerivedF::Scalar& vi) {
|
||||
guard_vertices.emplace_back(vertex_locks[vi]);
|
||||
});
|
||||
}
|
||||
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;
|
||||
}
|
||||
};
|
||||
size_t num_threads=0;
|
||||
const size_t hardware_limit = std::thread::hardware_concurrency();
|
||||
if (const char* igl_num_threads = std::getenv("LIBIGL_NUM_THREADS")) {
|
||||
num_threads = atoi(igl_num_threads);
|
||||
}
|
||||
if (num_threads == 0 || num_threads > hardware_limit) {
|
||||
num_threads = hardware_limit;
|
||||
}
|
||||
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
|
||||
80
src/igl/copyleft/cgal/assign.cpp
Normal file
80
src/igl/copyleft/cgal/assign.cpp
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
// 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 "assign_scalar.h"
|
||||
|
||||
template <typename DerivedC, typename DerivedD>
|
||||
IGL_INLINE void igl::copyleft::cgal::assign(
|
||||
const Eigen::MatrixBase<DerivedC> & C,
|
||||
Eigen::PlainObjectBase<DerivedD> & D)
|
||||
{
|
||||
D.resizeLike(C);
|
||||
for(int i = 0;i<C.rows();i++)
|
||||
{
|
||||
for(int j = 0;j<C.cols();j++)
|
||||
{
|
||||
assign_scalar(C(i,j),D(i,j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&);
|
||||
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, -1, 1, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&);
|
||||
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, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&);
|
||||
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, 0, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<double, 8, 3, 0, 8, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 8, 3, 0, 8, 3> >&);
|
||||
#endif
|
||||
42
src/igl/copyleft/cgal/assign.h
Normal file
42
src/igl/copyleft/cgal/assign.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// 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
|
||||
{
|
||||
template <typename DerivedC, typename DerivedD>
|
||||
IGL_INLINE void assign(
|
||||
const Eigen::MatrixBase<DerivedC> & C,
|
||||
Eigen::PlainObjectBase<DerivedD> & D);
|
||||
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
|
||||
136
src/igl/copyleft/cgal/assign_scalar.cpp
Normal file
136
src/igl/copyleft/cgal/assign_scalar.cpp
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
// 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"
|
||||
|
||||
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
|
||||
74
src/igl/copyleft/cgal/assign_scalar.h
Normal file
74
src/igl/copyleft/cgal/assign_scalar.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
// 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_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
|
||||
{
|
||||
// Inputs:
|
||||
// cgal cgal scalar
|
||||
// Outputs:
|
||||
// d output scalar
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Epeck::FT & cgal,
|
||||
CGAL::Epeck::FT & d);
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Epeck::FT & cgal,
|
||||
double & d);
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Epeck::FT & cgal,
|
||||
float& d);
|
||||
IGL_INLINE void assign_scalar(
|
||||
const double & c,
|
||||
double & d);
|
||||
IGL_INLINE void assign_scalar(
|
||||
const float& c,
|
||||
float & d);
|
||||
IGL_INLINE void assign_scalar(
|
||||
const float& c,
|
||||
double& d);
|
||||
|
||||
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);
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
|
||||
double & d);
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
|
||||
float& d);
|
||||
|
||||
#ifndef WIN32
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
|
||||
CGAL::Simple_cartesian<mpq_class>::FT & d);
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
|
||||
double & d);
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
|
||||
float& d);
|
||||
#endif // WIN32
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "assign_scalar.cpp"
|
||||
#endif
|
||||
#endif
|
||||
15
src/igl/copyleft/cgal/barycenter.cpp
Normal file
15
src/igl/copyleft/cgal/barycenter.cpp
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// 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"
|
||||
template void igl::barycenter<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
34
src/igl/copyleft/cgal/cell_adjacency.cpp
Normal file
34
src/igl/copyleft/cgal/cell_adjacency.cpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// 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
|
||||
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
|
||||
50
src/igl/copyleft/cgal/cell_adjacency.h
Normal file
50
src/igl/copyleft/cgal/cell_adjacency.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
// 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
|
||||
{
|
||||
// Inputs:
|
||||
// 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.
|
||||
// num_cells number of cells.
|
||||
//
|
||||
// Outputs:
|
||||
// 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
|
||||
504
src/igl/copyleft/cgal/closest_facet.cpp
Normal file
504
src/igl/copyleft/cgal/closest_facet.cpp
Normal file
|
|
@ -0,0 +1,504 @@
|
|||
// 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 uE2EType,
|
||||
typename DerivedEMAP,
|
||||
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 std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
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,uE2E,EMAP,VF,VFi,tree,triangles,in_I,R,S);
|
||||
}
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename DerivedP,
|
||||
typename uE2EType,
|
||||
typename DerivedEMAP,
|
||||
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 std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
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());
|
||||
auto eids = uE2E[ueid];
|
||||
std::vector<size_t> intersected_face_indices;
|
||||
for (auto eid : eids)
|
||||
{
|
||||
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 DerivedP,
|
||||
typename uE2EType,
|
||||
typename DerivedEMAP,
|
||||
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 std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
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, uE2E, EMAP, R, S);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::closest_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, unsigned long, 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::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > 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> > > > 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> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::closest_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, unsigned long, 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::Lazy_exact_nt<CGAL::Gmpq>, -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::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > 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> > > > 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> >&);
|
||||
template void igl::copyleft::cgal::closest_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, unsigned long, 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::Lazy_exact_nt<CGAL::Gmpq>, -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::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<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> >&);
|
||||
#ifdef WIN32
|
||||
template void igl::copyleft::cgal::closest_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class CGAL::Epeck, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class CGAL::AABB_tree<class CGAL::AABB_traits<class CGAL::Epeck, class CGAL::AABB_triangle_primitive<class CGAL::Epeck, class std::_Vector_iterator<class std::_Vector_val<struct std::_Simple_types<class CGAL::Triangle_3<class CGAL::Epeck>>>>, struct CGAL::Boolean_tag<0>>>> const &, class std::vector<class CGAL::Triangle_3<class CGAL::Epeck>, class std::allocator<class CGAL::Triangle_3<class CGAL::Epeck>>> const &, class std::vector<bool, class std::allocator<bool>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::closest_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class CGAL::Epeck, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class CGAL::AABB_tree<class CGAL::AABB_traits<class CGAL::Epeck, class CGAL::AABB_triangle_primitive<class CGAL::Epeck, class std::_Vector_iterator<class std::_Vector_val<struct std::_Simple_types<class CGAL::Triangle_3<class CGAL::Epeck>>>>, struct CGAL::Boolean_tag<0>>>> const &, class std::vector<class CGAL::Triangle_3<class CGAL::Epeck>, class std::allocator<class CGAL::Triangle_3<class CGAL::Epeck>>> const &, class std::vector<bool, class std::allocator<bool>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::closest_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class CGAL::Epeck, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class CGAL::AABB_tree<class CGAL::AABB_traits<class CGAL::Epeck, class CGAL::AABB_triangle_primitive<class CGAL::Epeck, class std::_Vector_iterator<class std::_Vector_val<struct std::_Simple_types<class CGAL::Triangle_3<class CGAL::Epeck>>>>, struct CGAL::Boolean_tag<0>>>> const &, class std::vector<class CGAL::Triangle_3<class CGAL::Epeck>, class std::allocator<class CGAL::Triangle_3<class CGAL::Epeck>>> const &, class std::vector<bool, class std::allocator<bool>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
|
||||
#endif
|
||||
#endif
|
||||
110
src/igl/copyleft/cgal/closest_facet.h
Normal file
110
src/igl/copyleft/cgal/closest_facet.h
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
// 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.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 array of vertices.
|
||||
// F #F by 3 array of faces.
|
||||
// I #I list of triangle indices to consider.
|
||||
// P #P by 3 array of query points.
|
||||
//
|
||||
// Outputs:
|
||||
// R #P list of closest facet indices.
|
||||
// S #P list of bools indicating on which side of the closest facet
|
||||
// each query point lies.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename DerivedP,
|
||||
typename uE2EType,
|
||||
typename DerivedEMAP,
|
||||
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 std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
Eigen::PlainObjectBase<DerivedR>& R,
|
||||
Eigen::PlainObjectBase<DerivedS>& S);
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename uE2EType,
|
||||
typename DerivedEMAP,
|
||||
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 std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
Eigen::PlainObjectBase<DerivedR>& R,
|
||||
Eigen::PlainObjectBase<DerivedS>& S);
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename DerivedP,
|
||||
typename uE2EType,
|
||||
typename DerivedEMAP,
|
||||
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 std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
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
|
||||
152
src/igl/copyleft/cgal/complex_to_mesh.cpp
Normal file
152
src/igl/copyleft/cgal/complex_to_mesh.cpp
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
// 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
|
||||
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
|
||||
47
src/igl/copyleft/cgal/complex_to_mesh.h
Normal file
47
src/igl/copyleft/cgal/complex_to_mesh.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// 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
|
||||
{
|
||||
// Templates:
|
||||
// Tr CGAL triangulation type, e.g.
|
||||
// CGAL::Surface_mesh_default_triangulation_3
|
||||
// Inputs
|
||||
// c2t3 2-complex (surface) living in a 3d triangulation (e.g. result of
|
||||
// CGAL::make_surface_mesh)
|
||||
// Outputs:
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices
|
||||
// Returns 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
|
||||
|
||||
83
src/igl/copyleft/cgal/component_inside_component.cpp
Normal file
83
src/igl/copyleft/cgal/component_inside_component.cpp
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
// 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
|
||||
75
src/igl/copyleft/cgal/component_inside_component.h
Normal file
75
src/igl/copyleft/cgal/component_inside_component.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// 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).
|
||||
//
|
||||
// Precondition:
|
||||
// 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).
|
||||
//
|
||||
// Inputs:
|
||||
// V1 #V1 by 3 list of vertex position of mesh 1
|
||||
// F1 #F1 by 3 list of triangles indices into V1
|
||||
// I1 #I1 list of indices into F1, indicate the facets of component
|
||||
// V2 #V2 by 3 list of vertex position of mesh 2
|
||||
// F2 #F2 by 3 list of triangles indices into V2
|
||||
// I2 #I2 list of indices into F2, indicate the facets of component
|
||||
//
|
||||
// Outputs:
|
||||
// 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);
|
||||
|
||||
// Determine if mesh (V1, F1) is inside of mesh (V2, F2).
|
||||
//
|
||||
// Precondition:
|
||||
// Both meshes must be closed, self-intersection free, non-degenerated
|
||||
// surfaces that are the boundary of 3D volumes. They should not
|
||||
// intersect each other.
|
||||
//
|
||||
// Inputs:
|
||||
// V1 #V1 by 3 list of vertex position of mesh 1
|
||||
// F1 #F1 by 3 list of triangles indices into V1
|
||||
// V2 #V2 by 3 list of vertex position of mesh 2
|
||||
// F2 #F2 by 3 list of triangles indices into V2
|
||||
//
|
||||
// Outputs:
|
||||
// return true iff (V1, F1) is entirely inside of (V2, F2).
|
||||
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
|
||||
72
src/igl/copyleft/cgal/convex_hull.cpp
Normal file
72
src/igl/copyleft/cgal/convex_hull.cpp
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
// 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.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;
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
// 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> >&);
|
||||
#endif
|
||||
56
src/igl/copyleft/cgal/convex_hull.h
Normal file
56
src/igl/copyleft/cgal/convex_hull.h
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
// 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)
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of input points
|
||||
// Outputs:
|
||||
// W #W by 3 list of convex hull points
|
||||
// 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);
|
||||
// Given a set of points (V), compute the convex hull as a triangle mesh (F)
|
||||
// over input vertex set (V)
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of input points
|
||||
// Outputs:
|
||||
// F #F by 3 list of triangle indices into V
|
||||
//
|
||||
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
|
||||
62
src/igl/copyleft/cgal/delaunay_triangulation.cpp
Normal file
62
src/igl/copyleft/cgal/delaunay_triangulation.cpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
// 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::PlainObjectBase<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++;
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
}
|
||||
|
||||
47
src/igl/copyleft/cgal/delaunay_triangulation.h
Normal file
47
src/igl/copyleft/cgal/delaunay_triangulation.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// 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.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 2 list of vertex positions
|
||||
//
|
||||
// Outputs:
|
||||
// F #F by 3 of faces in Delaunay triangulation.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF
|
||||
>
|
||||
IGL_INLINE void delaunay_triangulation(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
Eigen::PlainObjectBase<DerivedF>& F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "delaunay_triangulation.cpp"
|
||||
#endif
|
||||
#endif
|
||||
547
src/igl/copyleft/cgal/extract_cells.cpp
Normal file
547
src/igl/copyleft/cgal/extract_cells.cpp
Normal file
|
|
@ -0,0 +1,547 @@
|
|||
// 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 "closest_facet.h"
|
||||
#include "order_facets_around_edge.h"
|
||||
#include "outer_facet.h"
|
||||
#include "submesh_aabb_tree.h"
|
||||
#include "../../extract_manifold_patches.h"
|
||||
#include "../../facet_components.h"
|
||||
#include "../../get_seconds.h"
|
||||
#include "../../triangle_triangle_adjacency.h"
|
||||
#include "../../unique_edge_map.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_DEBUG
|
||||
|
||||
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;
|
||||
std::vector<std::vector<size_t> > uE2E;
|
||||
igl::unique_edge_map(F, E, uE, EMAP, uE2E);
|
||||
// Cluster into manifold patches
|
||||
Eigen::VectorXi P;
|
||||
igl::extract_manifold_patches(F, EMAP, uE2E, P);
|
||||
// Extract cells
|
||||
DerivedC per_patch_cells;
|
||||
const size_t num_cells =
|
||||
igl::copyleft::cgal::extract_cells(V,F,P,E,uE,uE2E,EMAP,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 num_cells;
|
||||
}
|
||||
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename DerivedE,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename DerivedEMAP,
|
||||
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 std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
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_DEBUG
|
||||
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 {
|
||||
std::cout << "extract_cells." << label << ": "
|
||||
<< tictoc() << std::endl;
|
||||
};
|
||||
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,uE2E,EMAP,raw_cells);
|
||||
log_time("extract_single_component_cells");
|
||||
|
||||
// Compute triangle-triangle adjacency data-structure
|
||||
std::vector<std::vector<std::vector<Index > > > TT,_1;
|
||||
igl::triangle_triangle_adjacency(E, EMAP, uE2E, 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);
|
||||
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);
|
||||
for (size_t i=0; i<num_components; 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]);
|
||||
}
|
||||
#ifdef EXTRACT_CELLS_DEBUG
|
||||
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>::min());
|
||||
// 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,
|
||||
uE2E,
|
||||
EMAP,
|
||||
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_DEBUG
|
||||
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_DEBUG
|
||||
log_time("finalize");
|
||||
#endif
|
||||
return count;
|
||||
}
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename DerivedEMAP,
|
||||
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 std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
Eigen::PlainObjectBase<DerivedC>& cells)
|
||||
{
|
||||
const size_t num_faces = F.rows();
|
||||
// Input:
|
||||
// index index into #F*3 list of undirect edges
|
||||
// Returns index into face
|
||||
const auto edge_index_to_face_index = [&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.
|
||||
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();
|
||||
if (num_adj_faces > 2) {
|
||||
for (size_t j=0; j<num_adj_faces; j++) {
|
||||
const size_t patch_j = P[edge_index_to_face_index(adj_faces[j])];
|
||||
for (size_t k=j+1; k<num_adj_faces; k++) {
|
||||
const size_t patch_k = P[edge_index_to_face_index(adj_faces[k])];
|
||||
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});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
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();
|
||||
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)
|
||||
{
|
||||
const size_t fid = edge_index_to_face_index(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);
|
||||
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[edge_index_to_face_index(adj_faces[order[curr_idx]])];
|
||||
const size_t next_patch_idx =
|
||||
P[edge_index_to_face_index(adj_faces[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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
assert((cells.array() != INVALID).all());
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template unsigned long igl::copyleft::cgal::extract_cells<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > 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<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > 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 unsigned long igl::copyleft::cgal::extract_cells<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
template unsigned long igl::copyleft::cgal::extract_cells<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template unsigned long igl::copyleft::cgal::extract_cells<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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::Lazy_exact_nt<CGAL::Gmpq>, -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 unsigned __int64 igl::copyleft::cgal::extract_cells<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &);
|
||||
template unsigned __int64 igl::copyleft::cgal::extract_cells<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &);
|
||||
template unsigned __int64 igl::copyleft::cgal::extract_cells<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &);
|
||||
#endif
|
||||
#endif
|
||||
116
src/igl/copyleft/cgal/extract_cells.h
Normal file
116
src/igl/copyleft/cgal/extract_cells.h
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
// 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
|
||||
#define IGL_COPYLEFT_CGAL_EXTRACT_CELLS
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
|
||||
namespace igl {
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Extract connected 3D space partitioned by mesh (V, F).
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 array of vertices.
|
||||
// F #F by 3 array of faces.
|
||||
//
|
||||
// Output:
|
||||
// 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.
|
||||
// Returns the number of cells
|
||||
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);
|
||||
|
||||
// Extract connected 3D space partitioned by mesh (V, F).
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 array of vertices.
|
||||
// F #F by 3 array of faces.
|
||||
// P #F list of patch indices.
|
||||
// E #E by 2 array of vertex indices, one edge per row.
|
||||
// uE #uE by 2 list of vertex_indices, represents undirected edges.
|
||||
// uE2E #uE list of lists that maps uE to E. (a one-to-many map)
|
||||
// EMAP #F*3 list of indices into uE.
|
||||
//
|
||||
// Output:
|
||||
// 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 negqtive side.
|
||||
// By convension cell with index 0 is the infinite cell.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename DerivedE,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename DerivedEMAP,
|
||||
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 std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
Eigen::PlainObjectBase<DerivedC>& cells);
|
||||
|
||||
// Extract connected 3D space partitioned by mesh (V,F) composed of
|
||||
// **possibly multiple components** (the name of this function is
|
||||
// dubious).
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 array of vertices.
|
||||
// F #F by 3 array of faces.
|
||||
// P #F list of patch indices.
|
||||
// E #E by 2 array of vertex indices, one edge per row.
|
||||
// uE #uE by 2 list of vertex_indices, represents undirected edges.
|
||||
// uE2E #uE list of lists that maps uE to E. (a one-to-many map)
|
||||
// EMAP #F*3 list of indices into uE.
|
||||
// Output:
|
||||
// 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.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename DerivedEMAP,
|
||||
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 std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
Eigen::PlainObjectBase<DerivedC>& cells);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "extract_cells.cpp"
|
||||
#endif
|
||||
#endif
|
||||
123
src/igl/copyleft/cgal/extract_feature.cpp
Normal file
123
src/igl/copyleft/cgal/extract_feature.cpp
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
// 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 <igl/unique_edge_map.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]);
|
||||
}
|
||||
}
|
||||
90
src/igl/copyleft/cgal/extract_feature.h
Normal file
90
src/igl/copyleft/cgal/extract_feature.h
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
// 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.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 array of vertices.
|
||||
// F #F by 3 array of faces.
|
||||
// tol Edges with dihedral angle larger than this are considered
|
||||
// as features. Angle is measured in radian.
|
||||
//
|
||||
// Output:
|
||||
// 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);
|
||||
|
||||
// Inputs:
|
||||
// V #V by 3 array of vertices.
|
||||
// F #F by 3 array of faces.
|
||||
// tol Edges with dihedral angle larger than this are considered
|
||||
// as features. Angle is measured in radian.
|
||||
// E #E by 2 array of directed edges.
|
||||
// uE #uE by 2 array of undirected edges.
|
||||
// uE2E #uE list of lists mapping undirected edges to all corresponding
|
||||
// directed edges.
|
||||
//
|
||||
// Output:
|
||||
// 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,
|
||||
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
|
||||
82
src/igl/copyleft/cgal/fast_winding_number.cpp
Normal file
82
src/igl/copyleft/cgal/fast_winding_number.cpp
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
#include "../../fast_winding_number.h"
|
||||
#include "../../octree.h"
|
||||
#include "../../knn.h"
|
||||
#include "../../parallel_for.h"
|
||||
#include "point_areas.h"
|
||||
#include <vector>
|
||||
|
||||
namespace igl {
|
||||
namespace copyleft{
|
||||
namespace cgal{
|
||||
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
|
||||
){
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
66
src/igl/copyleft/cgal/fast_winding_number.h
Normal file
66
src/igl/copyleft/cgal/fast_winding_number.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
#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
|
||||
{
|
||||
// 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
|
||||
//
|
||||
// Inputs:
|
||||
// P #P by 3 list of point locations
|
||||
// N #P by 3 list of point normals
|
||||
// Q #Q by 3 list of query points for the winding number
|
||||
// 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.
|
||||
// expansion_order the order of the taylor expansion. We support 0,1,2.
|
||||
// Outputs:
|
||||
// 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
|
||||
);
|
||||
|
||||
// Evaluate the fast winding number for point data, without known areas. The
|
||||
// areas are calculated using igl::knn and
|
||||
// igl::point_areas. This function uses the default expansion
|
||||
// order and beta (both are set to 2).
|
||||
//
|
||||
// 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 (described above).
|
||||
|
||||
// Inputs:
|
||||
// P #P by 3 list of point locations
|
||||
// N #P by 3 list of point normals
|
||||
// Q #Q by 3 list of query points for the winding number
|
||||
// Outputs:
|
||||
// WN #Q by 1 list of windinng number values at each query point
|
||||
//
|
||||
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
|
||||
|
||||
123
src/igl/copyleft/cgal/half_space_box.cpp
Normal file
123
src/igl/copyleft/cgal/half_space_box.cpp
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
#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
|
||||
// generated by autoexplicit.sh
|
||||
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::Lazy_exact_nt<CGAL::Gmpq>, 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::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>&, Eigen::Matrix<int, 12, 3, 0, 12, 3>&);
|
||||
template void igl::copyleft::cgal::half_space_box<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 4, 1, 1, 4>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 4, 1, 1, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>&, Eigen::Matrix<int, 12, 3, 0, 12, 3>&);
|
||||
template void igl::copyleft::cgal::half_space_box<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 4, 1, 1, 4>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 4, 0, -1, 4> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 4, 1, 1, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 4, 0, -1, 4> > const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>&, Eigen::Matrix<int, 12, 3, 0, 12, 3>&);
|
||||
template void igl::copyleft::cgal::half_space_box<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 4, 1, 1, 4>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 4, 1, 1, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 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::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>&, Eigen::Matrix<int, 12, 3, 0, 12, 3>&);
|
||||
#endif
|
||||
63
src/igl/copyleft/cgal/half_space_box.h
Normal file
63
src/igl/copyleft/cgal/half_space_box.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#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).
|
||||
//
|
||||
// Inputs:
|
||||
// P plane so that normal points away from half-space
|
||||
// V #V by 3 list of vertex positions
|
||||
// Outputs:
|
||||
// BV #BV by 3 list of box vertex positions
|
||||
// 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);
|
||||
// Inputs:
|
||||
// p 3d point on plane
|
||||
// n 3d vector of normal of plane pointing away from inside
|
||||
// V #V by 3 list of vertex positions
|
||||
// Outputs:
|
||||
// BV #BV by 3 list of box vertex positions
|
||||
// BF #BF b3 list of box triangle indices into BV
|
||||
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);
|
||||
// Inputs:
|
||||
// equ plane equation: a*x+b*y+c*z + d = 0
|
||||
// V #V by 3 list of vertex positions
|
||||
// Outputs:
|
||||
// BV #BV by 3 list of box vertex positions
|
||||
// BF #BF b3 list of box triangle indices into BV
|
||||
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
|
||||
39
src/igl/copyleft/cgal/hausdorff.cpp
Normal file
39
src/igl/copyleft/cgal/hausdorff.cpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#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);
|
||||
}
|
||||
62
src/igl/copyleft/cgal/hausdorff.h
Normal file
62
src/igl/copyleft/cgal/hausdorff.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
// 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).
|
||||
//
|
||||
// Inputs:
|
||||
// V 3 by 3 list of corner positions so that V.row(i) is the position of the
|
||||
// ith corner
|
||||
// treeB CGAL's AABB tree containing triangle soup (VB,FB)
|
||||
// TB list of CGAL triangles in order of FB (for determining which was found
|
||||
// in computation)
|
||||
// Outputs:
|
||||
// l lower bound on Hausdorff distance
|
||||
// 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
|
||||
|
||||
|
||||
39
src/igl/copyleft/cgal/incircle.cpp
Normal file
39
src/igl/copyleft/cgal/incircle.cpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// 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[2],
|
||||
const Scalar pb[2],
|
||||
const Scalar pc[2],
|
||||
const Scalar pd[2])
|
||||
{
|
||||
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";
|
||||
}
|
||||
}
|
||||
39
src/igl/copyleft/cgal/incircle.h
Normal file
39
src/igl/copyleft/cgal/incircle.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// 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
|
||||
{
|
||||
// Inputs:
|
||||
// pa,pb,pc,pd 2D points.
|
||||
// Output:
|
||||
// 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[2],
|
||||
const Scalar pb[2],
|
||||
const Scalar pc[2],
|
||||
const Scalar pd[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "incircle.cpp"
|
||||
#endif
|
||||
#endif
|
||||
68
src/igl/copyleft/cgal/insert_into_cdt.cpp
Normal file
68
src/igl/copyleft/cgal/insert_into_cdt.cpp
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson
|
||||
//
|
||||
// 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 "insert_into_cdt.h"
|
||||
#include <CGAL/Point_3.h>
|
||||
#include <CGAL/Segment_3.h>
|
||||
#include <CGAL/Triangle_3.h>
|
||||
|
||||
template <typename Kernel>
|
||||
IGL_INLINE void igl::copyleft::cgal::insert_into_cdt(
|
||||
const CGAL::Object & obj,
|
||||
const CGAL::Plane_3<Kernel> & P,
|
||||
CGAL::Constrained_triangulation_plus_2<
|
||||
CGAL::Constrained_Delaunay_triangulation_2<
|
||||
Kernel,
|
||||
CGAL::Triangulation_data_structure_2<
|
||||
CGAL::Triangulation_vertex_base_2<Kernel>,
|
||||
CGAL::Constrained_triangulation_face_base_2< Kernel>
|
||||
>,
|
||||
CGAL::Exact_intersections_tag
|
||||
>
|
||||
>
|
||||
& cdt)
|
||||
{
|
||||
typedef CGAL::Point_3<Kernel> Point_3;
|
||||
typedef CGAL::Segment_3<Kernel> Segment_3;
|
||||
typedef CGAL::Triangle_3<Kernel> Triangle_3;
|
||||
|
||||
if(const Segment_3 *iseg = CGAL::object_cast<Segment_3 >(&obj))
|
||||
{
|
||||
// Add segment constraint
|
||||
cdt.insert_constraint( P.to_2d(iseg->vertex(0)),P.to_2d(iseg->vertex(1)));
|
||||
}else if(const Point_3 *ipoint = CGAL::object_cast<Point_3 >(&obj))
|
||||
{
|
||||
// Add point
|
||||
cdt.insert(P.to_2d(*ipoint));
|
||||
} else if(const Triangle_3 *itri = CGAL::object_cast<Triangle_3 >(&obj))
|
||||
{
|
||||
// Add 3 segment constraints
|
||||
cdt.insert_constraint( P.to_2d(itri->vertex(0)),P.to_2d(itri->vertex(1)));
|
||||
cdt.insert_constraint( P.to_2d(itri->vertex(1)),P.to_2d(itri->vertex(2)));
|
||||
cdt.insert_constraint( P.to_2d(itri->vertex(2)),P.to_2d(itri->vertex(0)));
|
||||
} else if(const std::vector<Point_3 > *polyp =
|
||||
CGAL::object_cast< std::vector<Point_3 > >(&obj))
|
||||
{
|
||||
const std::vector<Point_3 > & poly = *polyp;
|
||||
const size_t m = poly.size();
|
||||
assert(m>=2);
|
||||
for(size_t p = 0;p<m;p++)
|
||||
{
|
||||
const size_t np = (p+1)%m;
|
||||
cdt.insert_constraint(P.to_2d(poly[p]),P.to_2d(poly[np]));
|
||||
}
|
||||
}else {
|
||||
throw std::runtime_error("Unknown intersection object!");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
template void igl::copyleft::cgal::insert_into_cdt<CGAL::Epick>(CGAL::Object const&, CGAL::Plane_3<CGAL::Epick> const&, CGAL::Constrained_triangulation_plus_2<CGAL::Constrained_Delaunay_triangulation_2<CGAL::Epick, CGAL::Triangulation_data_structure_2<CGAL::Triangulation_vertex_base_2<CGAL::Epick, CGAL::Triangulation_ds_vertex_base_2<void> >, CGAL::Constrained_triangulation_face_base_2<CGAL::Epick, CGAL::Triangulation_face_base_2<CGAL::Epick, CGAL::Triangulation_ds_face_base_2<void> > > >, CGAL::Exact_intersections_tag> >&);
|
||||
template void igl::copyleft::cgal::insert_into_cdt<CGAL::Epeck>(CGAL::Object const&, CGAL::Plane_3<CGAL::Epeck> const&, CGAL::Constrained_triangulation_plus_2<CGAL::Constrained_Delaunay_triangulation_2<CGAL::Epeck, CGAL::Triangulation_data_structure_2<CGAL::Triangulation_vertex_base_2<CGAL::Epeck, CGAL::Triangulation_ds_vertex_base_2<void> >, CGAL::Constrained_triangulation_face_base_2<CGAL::Epeck, CGAL::Triangulation_face_base_2<CGAL::Epeck, CGAL::Triangulation_ds_face_base_2<void> > > >, CGAL::Exact_intersections_tag> >&);
|
||||
#endif
|
||||
60
src/igl/copyleft/cgal/insert_into_cdt.h
Normal file
60
src/igl/copyleft/cgal/insert_into_cdt.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson
|
||||
//
|
||||
// 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_INSERT_INTO_CDT_H
|
||||
#define IGL_COPYLEFT_CGAL_INSERT_INTO_CDT_H
|
||||
#include "../../igl_inline.h"
|
||||
|
||||
#include <CGAL/double.h> // Workaround https://github.com/CGAL/cgal/issues/2182 with CGAL 4.10-1
|
||||
#include <CGAL/Plane_3.h>
|
||||
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
|
||||
#include <CGAL/Constrained_triangulation_plus_2.h>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Given a current 2D constrained Delaunay triangulation (cdt), insert a
|
||||
// 3D "object" (e.g., resulting from intersecting two triangles) into the
|
||||
// cdt, by projecting it via the given plane (P) and adding appropriate
|
||||
// constraints.
|
||||
//
|
||||
// Inputs:
|
||||
// obj CGAL::Object representing a vertex, segment, or (convex)
|
||||
// polygon. All vertices should lie on the plane P. If not, then this
|
||||
// adds the _projection_ of this object to the cdt and that might not
|
||||
// be what you wanted to do.
|
||||
// P plane obj lies on and upon which the cdt is being performed
|
||||
// cdt current CDT, see output
|
||||
// Outputs:
|
||||
// cdt CDT updated to contain constraints for the given object
|
||||
//
|
||||
template <typename Kernel>
|
||||
IGL_INLINE void insert_into_cdt(
|
||||
const CGAL::Object & obj,
|
||||
const CGAL::Plane_3<Kernel> & P,
|
||||
CGAL::Constrained_triangulation_plus_2<
|
||||
CGAL::Constrained_Delaunay_triangulation_2<
|
||||
Kernel,
|
||||
CGAL::Triangulation_data_structure_2<
|
||||
CGAL::Triangulation_vertex_base_2<Kernel>,
|
||||
CGAL::Constrained_triangulation_face_base_2< Kernel>
|
||||
>,
|
||||
CGAL::Exact_intersections_tag
|
||||
>
|
||||
>
|
||||
& cdt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "insert_into_cdt.cpp"
|
||||
#endif
|
||||
#endif
|
||||
41
src/igl/copyleft/cgal/insphere.cpp
Normal file
41
src/igl/copyleft/cgal/insphere.cpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// 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 "insphere.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::insphere(
|
||||
const Scalar pa[3],
|
||||
const Scalar pb[3],
|
||||
const Scalar pc[3],
|
||||
const Scalar pd[3],
|
||||
const Scalar pe[3])
|
||||
{
|
||||
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_sphere(
|
||||
typename Kernel::Point_3(pa[0], pa[1], pa[2]),
|
||||
typename Kernel::Point_3(pb[0], pb[1], pb[2]),
|
||||
typename Kernel::Point_3(pc[0], pc[1], pc[2]),
|
||||
typename Kernel::Point_3(pd[0], pd[1], pd[2]),
|
||||
typename Kernel::Point_3(pe[0], pe[1], pe[2]))) {
|
||||
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";
|
||||
}
|
||||
}
|
||||
40
src/igl/copyleft/cgal/insphere.h
Normal file
40
src/igl/copyleft/cgal/insphere.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// 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_INSPHERE_H
|
||||
#define IGL_COPYLEFT_CGAL_INSPHERE_H
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Inputs:
|
||||
// pa,pb,pc,pd,pe 3D points.
|
||||
// Output:
|
||||
// 1 if pe is inside of the oriented sphere formed by pa,pb,pc,pd.
|
||||
// 0 if pe is co-spherical with pa,pb,pc,pd.
|
||||
// -1 if pe is outside of the oriented sphere formed by pa,pb,pc,pd.
|
||||
template <typename Scalar>
|
||||
IGL_INLINE short insphere(
|
||||
const Scalar pa[3],
|
||||
const Scalar pb[3],
|
||||
const Scalar pc[3],
|
||||
const Scalar pd[3],
|
||||
const Scalar pe[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "insphere.cpp"
|
||||
#endif
|
||||
#endif
|
||||
289
src/igl/copyleft/cgal/intersect_other.cpp
Normal file
289
src/igl/copyleft/cgal/intersect_other.cpp
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
// 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 "intersect_other.h"
|
||||
#include "CGAL_includes.hpp"
|
||||
#include "mesh_to_cgal_triangle_list.h"
|
||||
#include "remesh_intersections.h"
|
||||
#include "../../slice_mask.h"
|
||||
#include "../../remove_unreferenced.h"
|
||||
|
||||
#ifndef IGL_FIRST_HIT_EXCEPTION
|
||||
#define IGL_FIRST_HIT_EXCEPTION 10
|
||||
#endif
|
||||
|
||||
// Un-exposed helper functions
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
template <typename DerivedF>
|
||||
static IGL_INLINE void push_result(
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
const int f,
|
||||
const int f_other,
|
||||
const CGAL::Object & result,
|
||||
std::map<
|
||||
typename DerivedF::Index,
|
||||
std::vector<std::pair<typename DerivedF::Index, CGAL::Object> > > &
|
||||
offending)
|
||||
//std::map<
|
||||
// std::pair<typename DerivedF::Index,typename DerivedF::Index>,
|
||||
// std::vector<typename DerivedF::Index> > & edge2faces)
|
||||
{
|
||||
typedef typename DerivedF::Index Index;
|
||||
typedef std::pair<Index,Index> EMK;
|
||||
if(offending.count(f) == 0)
|
||||
{
|
||||
// first time marking, initialize with new id and empty list
|
||||
offending[f] = {};
|
||||
for(Index e = 0; e<3;e++)
|
||||
{
|
||||
// append face to edge's list
|
||||
Index i = F(f,(e+1)%3) < F(f,(e+2)%3) ? F(f,(e+1)%3) : F(f,(e+2)%3);
|
||||
Index j = F(f,(e+1)%3) < F(f,(e+2)%3) ? F(f,(e+2)%3) : F(f,(e+1)%3);
|
||||
//edge2faces[EMK(i,j)].push_back(f);
|
||||
}
|
||||
}
|
||||
offending[f].push_back({f_other,result});
|
||||
}
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedIF,
|
||||
typename DerivedVVAB,
|
||||
typename DerivedFFAB,
|
||||
typename DerivedJAB,
|
||||
typename DerivedIMAB>
|
||||
static IGL_INLINE bool intersect_other_helper(
|
||||
const Eigen::PlainObjectBase<DerivedVA> & VA,
|
||||
const Eigen::PlainObjectBase<DerivedFA> & FA,
|
||||
const Eigen::PlainObjectBase<DerivedVB> & VB,
|
||||
const Eigen::PlainObjectBase<DerivedFB> & FB,
|
||||
const RemeshSelfIntersectionsParam & params,
|
||||
Eigen::PlainObjectBase<DerivedIF> & IF,
|
||||
Eigen::PlainObjectBase<DerivedVVAB> & VVAB,
|
||||
Eigen::PlainObjectBase<DerivedFFAB> & FFAB,
|
||||
Eigen::PlainObjectBase<DerivedJAB> & JAB,
|
||||
Eigen::PlainObjectBase<DerivedIMAB> & IMAB)
|
||||
{
|
||||
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
|
||||
typedef typename DerivedFA::Index Index;
|
||||
// 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::Triangulation_vertex_base_2<Kernel> TVB_2;
|
||||
typedef CGAL::Constrained_triangulation_face_base_2<Kernel> CTAB_2;
|
||||
typedef CGAL::Triangulation_data_structure_2<TVB_2,CTAB_2> TDS_2;
|
||||
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;
|
||||
typedef
|
||||
std::map<Index,std::vector<std::pair<Index,CGAL::Object> > >
|
||||
OffendingMap;
|
||||
typedef std::map<std::pair<Index,Index>,std::vector<Index> > EdgeMap;
|
||||
typedef std::pair<Index,Index> EMK;
|
||||
|
||||
Triangles TA,TB;
|
||||
// Compute and process self intersections
|
||||
mesh_to_cgal_triangle_list(VA,FA,TA);
|
||||
mesh_to_cgal_triangle_list(VB,FB,TB);
|
||||
// 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> A_boxes,B_boxes;
|
||||
const auto box_up = [](Triangles & T, std::vector<Box> & boxes) -> void
|
||||
{
|
||||
boxes.reserve(T.size());
|
||||
for (
|
||||
TrianglesIterator tit = T.begin();
|
||||
tit != T.end();
|
||||
++tit)
|
||||
{
|
||||
boxes.push_back(Box(tit->bbox(), tit));
|
||||
}
|
||||
};
|
||||
box_up(TA,A_boxes);
|
||||
box_up(TB,B_boxes);
|
||||
OffendingMap offendingA,offendingB;
|
||||
//EdgeMap edge2facesA,edge2facesB;
|
||||
|
||||
std::list<int> lIF;
|
||||
const auto cb = [&](const Box &a, const Box &b) -> void
|
||||
{
|
||||
using namespace std;
|
||||
// index in F and T
|
||||
int fa = a.handle()-TA.begin();
|
||||
int fb = b.handle()-TB.begin();
|
||||
const Triangle_3 & A = *a.handle();
|
||||
const Triangle_3 & B = *b.handle();
|
||||
if(CGAL::do_intersect(A,B))
|
||||
{
|
||||
// There was an intersection
|
||||
lIF.push_back(fa);
|
||||
lIF.push_back(fb);
|
||||
if(params.first_only)
|
||||
{
|
||||
throw IGL_FIRST_HIT_EXCEPTION;
|
||||
}
|
||||
if(!params.detect_only)
|
||||
{
|
||||
CGAL::Object result = CGAL::intersection(A,B);
|
||||
|
||||
push_result(FA,fa,fb,result,offendingA);
|
||||
push_result(FB,fb,fa,result,offendingB);
|
||||
}
|
||||
}
|
||||
};
|
||||
try{
|
||||
CGAL::box_intersection_d(
|
||||
A_boxes.begin(), A_boxes.end(),
|
||||
B_boxes.begin(), B_boxes.end(),
|
||||
cb);
|
||||
}catch(int e)
|
||||
{
|
||||
// Rethrow if not FIRST_HIT_EXCEPTION
|
||||
if(e != IGL_FIRST_HIT_EXCEPTION)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
// Otherwise just fall through
|
||||
}
|
||||
|
||||
// Convert lIF to Eigen matrix
|
||||
assert(lIF.size()%2 == 0);
|
||||
IF.resize(lIF.size()/2,2);
|
||||
{
|
||||
int i=0;
|
||||
for(
|
||||
list<int>::const_iterator ifit = lIF.begin();
|
||||
ifit!=lIF.end();
|
||||
)
|
||||
{
|
||||
IF(i,0) = (*ifit);
|
||||
ifit++;
|
||||
IF(i,1) = (*ifit);
|
||||
ifit++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if(!params.detect_only)
|
||||
{
|
||||
// Obsolete, now remesh_intersections expects a single mesh
|
||||
// remesh_intersections(VA,FA,TA,offendingA,VVA,FFA,JA,IMA);
|
||||
// remesh_intersections(VB,FB,TB,offendingB,VVB,FFB,JB,IMB);
|
||||
// Combine mesh and offending maps
|
||||
DerivedVA VAB(VA.rows()+VB.rows(),3);
|
||||
VAB<<VA,VB;
|
||||
DerivedFA FAB(FA.rows()+FB.rows(),3);
|
||||
FAB<<FA,(FB.array()+VA.rows());
|
||||
Triangles TAB;
|
||||
TAB.reserve(TA.size()+TB.size());
|
||||
TAB.insert(TAB.end(),TA.begin(),TA.end());
|
||||
TAB.insert(TAB.end(),TB.begin(),TB.end());
|
||||
OffendingMap offending;
|
||||
//offending.reserve(offendingA.size() + offendingB.size());
|
||||
for (const auto itr : offendingA)
|
||||
{
|
||||
// Remap offenders in FB to FAB
|
||||
auto offenders = itr.second;
|
||||
for(auto & offender : offenders)
|
||||
{
|
||||
offender.first += FA.rows();
|
||||
}
|
||||
offending[itr.first] = offenders;
|
||||
}
|
||||
for (const auto itr : offendingB)
|
||||
{
|
||||
// Store offenders for FB according to place in FAB
|
||||
offending[FA.rows() + itr.first] = itr.second;
|
||||
}
|
||||
|
||||
remesh_intersections(
|
||||
VAB,FAB,TAB,offending,params.stitch_all,VVAB,FFAB,JAB,IMAB);
|
||||
}
|
||||
|
||||
return IF.rows() > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedIF,
|
||||
typename DerivedVVAB,
|
||||
typename DerivedFFAB,
|
||||
typename DerivedJAB,
|
||||
typename DerivedIMAB>
|
||||
IGL_INLINE bool igl::copyleft::cgal::intersect_other(
|
||||
const Eigen::PlainObjectBase<DerivedVA> & VA,
|
||||
const Eigen::PlainObjectBase<DerivedFA> & FA,
|
||||
const Eigen::PlainObjectBase<DerivedVB> & VB,
|
||||
const Eigen::PlainObjectBase<DerivedFB> & FB,
|
||||
const RemeshSelfIntersectionsParam & params,
|
||||
Eigen::PlainObjectBase<DerivedIF> & IF,
|
||||
Eigen::PlainObjectBase<DerivedVVAB> & VVAB,
|
||||
Eigen::PlainObjectBase<DerivedFFAB> & FFAB,
|
||||
Eigen::PlainObjectBase<DerivedJAB> & JAB,
|
||||
Eigen::PlainObjectBase<DerivedIMAB> & IMAB)
|
||||
{
|
||||
if(params.detect_only)
|
||||
{
|
||||
return intersect_other_helper<CGAL::Epick>
|
||||
(VA,FA,VB,FB,params,IF,VVAB,FFAB,JAB,IMAB);
|
||||
}else
|
||||
{
|
||||
return intersect_other_helper<CGAL::Epeck>
|
||||
(VA,FA,VB,FB,params,IF,VVAB,FFAB,JAB,IMAB);
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE bool igl::copyleft::cgal::intersect_other(
|
||||
const Eigen::MatrixXd & VA,
|
||||
const Eigen::MatrixXi & FA,
|
||||
const Eigen::MatrixXd & VB,
|
||||
const Eigen::MatrixXi & FB,
|
||||
const bool first_only,
|
||||
Eigen::MatrixXi & IF)
|
||||
{
|
||||
Eigen::MatrixXd VVAB;
|
||||
Eigen::MatrixXi FFAB;
|
||||
Eigen::VectorXi JAB,IMAB;
|
||||
return intersect_other(
|
||||
VA,FA,VB,FB,{true,first_only},IF,VVAB,FFAB,JAB,IMAB);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template bool igl::copyleft::cgal::intersect_other<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<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, 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<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&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::intersect_other<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
91
src/igl/copyleft/cgal/intersect_other.h
Normal file
91
src/igl/copyleft/cgal/intersect_other.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
// 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_INTERSECT_OTHER_H
|
||||
#define IGL_COPYLEFT_CGAL_INTERSECT_OTHER_H
|
||||
#include "../../igl_inline.h"
|
||||
#include "RemeshSelfIntersectionsParam.h"
|
||||
|
||||
#include <Eigen/Dense>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// INTERSECT_OTHER Given a triangle mesh (VA,FA) and another mesh (VB,FB)
|
||||
// find all pairs of intersecting faces. Note that self-intersections are
|
||||
// ignored.
|
||||
//
|
||||
// Inputs:
|
||||
// VA #V by 3 list of vertex positions
|
||||
// FA #F by 3 list of triangle indices into VA
|
||||
// VB #V by 3 list of vertex positions
|
||||
// FB #F by 3 list of triangle indices into VB
|
||||
// params whether to detect only and then whether to only find first
|
||||
// intersection
|
||||
// Outputs:
|
||||
// IF #intersecting face pairs by 2 list of intersecting face pairs,
|
||||
// indexing FA and FB
|
||||
// VVAB #VVAB by 3 list of vertex positions
|
||||
// FFAB #FFAB by 3 list of triangle indices into VVA
|
||||
// JAB #FFAB list of indices into [FA;FB] denoting birth triangle
|
||||
// IMAB #VVAB list of indices stitching duplicates (resulting from
|
||||
// mesh intersections) together
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedIF,
|
||||
typename DerivedVVAB,
|
||||
typename DerivedFFAB,
|
||||
typename DerivedJAB,
|
||||
typename DerivedIMAB>
|
||||
IGL_INLINE bool intersect_other(
|
||||
const Eigen::PlainObjectBase<DerivedVA> & VA,
|
||||
const Eigen::PlainObjectBase<DerivedFA> & FA,
|
||||
const Eigen::PlainObjectBase<DerivedVB> & VB,
|
||||
const Eigen::PlainObjectBase<DerivedFB> & FB,
|
||||
const RemeshSelfIntersectionsParam & params,
|
||||
Eigen::PlainObjectBase<DerivedIF> & IF,
|
||||
Eigen::PlainObjectBase<DerivedVVAB> & VVAB,
|
||||
Eigen::PlainObjectBase<DerivedFFAB> & FFAB,
|
||||
Eigen::PlainObjectBase<DerivedJAB> & JAB,
|
||||
Eigen::PlainObjectBase<DerivedIMAB> & IMAB);
|
||||
// Legacy wrapper for detect only using common types.
|
||||
//
|
||||
// Inputs:
|
||||
// VA #V by 3 list of vertex positions
|
||||
// FA #F by 3 list of triangle indices into VA
|
||||
// VB #V by 3 list of vertex positions
|
||||
// FB #F by 3 list of triangle indices into VB
|
||||
// first_only whether to only detect the first intersection.
|
||||
// Outputs:
|
||||
// IF #intersecting face pairs by 2 list of intersecting face pairs,
|
||||
// indexing FA and FB
|
||||
// Returns true if any intersections were found
|
||||
//
|
||||
// See also: remesh_self_intersections
|
||||
IGL_INLINE bool intersect_other(
|
||||
const Eigen::MatrixXd & VA,
|
||||
const Eigen::MatrixXi & FA,
|
||||
const Eigen::MatrixXd & VB,
|
||||
const Eigen::MatrixXi & FB,
|
||||
const bool first_only,
|
||||
Eigen::MatrixXi & IF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "intersect_other.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
88
src/igl/copyleft/cgal/intersect_with_half_space.cpp
Normal file
88
src/igl/copyleft/cgal/intersect_with_half_space.cpp
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
#include "intersect_with_half_space.h"
|
||||
#include "mesh_boolean.h"
|
||||
#include "half_space_box.h"
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename Derivedp,
|
||||
typename Derivedn,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool igl::copyleft::cgal::intersect_with_half_space(
|
||||
const Eigen::MatrixBase<DerivedV > & V,
|
||||
const Eigen::MatrixBase<DerivedF > & F,
|
||||
const Eigen::MatrixBase<Derivedp > & p,
|
||||
const Eigen::MatrixBase<Derivedn > & n,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J)
|
||||
{
|
||||
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 intersect_with_half_space(V,F,P,VC,FC,J);
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename Derivedequ,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool igl::copyleft::cgal::intersect_with_half_space(
|
||||
const Eigen::MatrixBase<DerivedV > & V,
|
||||
const Eigen::MatrixBase<DerivedF > & F,
|
||||
const Eigen::MatrixBase<Derivedequ > & equ,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J)
|
||||
{
|
||||
typedef CGAL::Plane_3<CGAL::Epeck> Plane;
|
||||
Plane P(equ(0),equ(1),equ(2),equ(3));
|
||||
return intersect_with_half_space(V,F,P,VC,FC,J);
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool igl::copyleft::cgal::intersect_with_half_space(
|
||||
const Eigen::MatrixBase<DerivedV > & V,
|
||||
const Eigen::MatrixBase<DerivedF > & F,
|
||||
const CGAL::Plane_3<CGAL::Epeck> & P,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J)
|
||||
{
|
||||
Eigen::Matrix<CGAL::Epeck::FT,8,3> BV;
|
||||
Eigen::Matrix<int,12,3> BF;
|
||||
half_space_box(P,V,BV,BF);
|
||||
// Disturbingly, (BV,BF) must be first argument
|
||||
const bool ret = mesh_boolean(BV,BF,V,F,MESH_BOOLEAN_TYPE_INTERSECT,VC,FC,J);
|
||||
// But now J is wrong...
|
||||
std::for_each(
|
||||
J.data(),
|
||||
J.data()+J.size(),
|
||||
[&BF,&F](typename DerivedJ::Scalar & j)
|
||||
{j = (j<BF.rows()?F.rows()+j:j-BF.rows());}
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template bool igl::copyleft::cgal::intersect_with_half_space<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<double, 1, 3, 1, 1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -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<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, 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 bool igl::copyleft::cgal::intersect_with_half_space<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::CwiseUnaryOp<Eigen::internal::scalar_opposite_op<double>, Eigen::Matrix<double, 1, 3, 1, 1, 3> const>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::CwiseUnaryOp<Eigen::internal::scalar_opposite_op<double>, Eigen::Matrix<double, 1, 3, 1, 1, 3> const> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, 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 bool igl::copyleft::cgal::intersect_with_half_space<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::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -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<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, 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 bool igl::copyleft::cgal::intersect_with_half_space<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::CwiseUnaryOp<Eigen::internal::scalar_opposite_op<float>, Eigen::Matrix<float, 1, 3, 1, 1, 3> const>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::CwiseUnaryOp<Eigen::internal::scalar_opposite_op<float>, Eigen::Matrix<float, 1, 3, 1, 1, 3> const> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
96
src/igl/copyleft/cgal/intersect_with_half_space.h
Normal file
96
src/igl/copyleft/cgal/intersect_with_half_space.h
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
#ifndef IGL_COPYLEFT_CGAL_INTERSECT_WITH_HALF_SPACE_H
|
||||
#define IGL_COPYLEFT_CGAL_INTERSECT_WITH_HALF_SPACE_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
|
||||
{
|
||||
// Intersect a PWN mesh with a half-space. Point on plane, normal pointing
|
||||
// outward.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of mesh vertex positions
|
||||
// p 3d point on plane
|
||||
// n 3d vector of normal of plane pointing away from inside
|
||||
// Outputs:
|
||||
// VC #VC by 3 list of vertex positions of boolean result mesh
|
||||
// FC #FC by 3 list of triangle indices into VC
|
||||
// J #FC list of indices into [F;F.rows()+[1;2]] revealing "birth"
|
||||
// facet
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename Derivedp,
|
||||
typename Derivedn,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool intersect_with_half_space(
|
||||
const Eigen::MatrixBase<DerivedV > & V,
|
||||
const Eigen::MatrixBase<DerivedF > & F,
|
||||
const Eigen::MatrixBase<Derivedp > & p,
|
||||
const Eigen::MatrixBase<Derivedn > & n,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J);
|
||||
// Intersect a PWN mesh with a half-space. Plane equation.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of mesh vertex positions
|
||||
// equ plane equation: P(x,y,z) = a*x+b*y+c*z + d = 0, P(x,y,z) < 0 is
|
||||
// _inside_.
|
||||
// Outputs:
|
||||
// VC #VC by 3 list of vertex positions of boolean result mesh
|
||||
// FC #FC by 3 list of triangle indices into VC
|
||||
// J #FC list of indices into [F;F.rows()+[1;2]] revealing "birth" facet
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename Derivedequ,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool intersect_with_half_space(
|
||||
const Eigen::MatrixBase<DerivedV > & V,
|
||||
const Eigen::MatrixBase<DerivedF > & F,
|
||||
const Eigen::MatrixBase<Derivedequ > & equ,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J);
|
||||
// Intersect a PWN mesh with a half-space. CGAL Plane.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of mesh vertex positions
|
||||
// P plane
|
||||
// Outputs:
|
||||
// VC #VC by 3 list of vertex positions of boolean result mesh
|
||||
// FC #FC by 3 list of triangle indices into VC
|
||||
// J #FC list of indices into [F;F.rows()+[1;2]] revealing "birth" facet
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool intersect_with_half_space(
|
||||
const Eigen::MatrixBase<DerivedV > & V,
|
||||
const Eigen::MatrixBase<DerivedF > & F,
|
||||
const CGAL::Plane_3<CGAL::Epeck> & P,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "intersect_with_half_space.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
24
src/igl/copyleft/cgal/lexicographic_triangulation.cpp
Normal file
24
src/igl/copyleft/cgal/lexicographic_triangulation.cpp
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
|
||||
// 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 "lexicographic_triangulation.h"
|
||||
#include "../../lexicographic_triangulation.h"
|
||||
#include "orient2D.h"
|
||||
|
||||
template<
|
||||
typename DerivedP,
|
||||
typename DerivedF
|
||||
>
|
||||
IGL_INLINE void igl::copyleft::cgal::lexicographic_triangulation(
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
Eigen::PlainObjectBase<DerivedF>& F)
|
||||
{
|
||||
typedef typename DerivedP::Scalar Scalar;
|
||||
igl::lexicographic_triangulation(P, orient2D<Scalar>, F);
|
||||
}
|
||||
47
src/igl/copyleft/cgal/lexicographic_triangulation.h
Normal file
47
src/igl/copyleft/cgal/lexicographic_triangulation.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
|
||||
// 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_LEXICOGRAPHIC_TRIANGULATION_H
|
||||
#define IGL_COPYLEFT_CGAL_LEXICOGRAPHIC_TRIANGULATION_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
|
||||
// Given a set of points in 2D, return a lexicographic triangulation of these
|
||||
// points.
|
||||
//
|
||||
// Inputs:
|
||||
// P #P by 2 list of vertex positions
|
||||
//
|
||||
// Outputs:
|
||||
// F #F by 3 of faces in lexicographic triangulation.
|
||||
template<
|
||||
typename DerivedP,
|
||||
typename DerivedF
|
||||
>
|
||||
IGL_INLINE void lexicographic_triangulation(
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
Eigen::PlainObjectBase<DerivedF>& F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "lexicographic_triangulation.cpp"
|
||||
#endif
|
||||
#endif
|
||||
15
src/igl/copyleft/cgal/list_to_matrix.cpp
Normal file
15
src/igl/copyleft/cgal/list_to_matrix.cpp
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// 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 "../../list_to_matrix.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 "../../list_to_matrix.cpp"
|
||||
template bool igl::list_to_matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >(std::vector<std::vector<CGAL::Lazy_exact_nt<CGAL::Gmpq>, std::allocator<CGAL::Lazy_exact_nt<CGAL::Gmpq> > >, std::allocator<std::vector<CGAL::Lazy_exact_nt<CGAL::Gmpq>, std::allocator<CGAL::Lazy_exact_nt<CGAL::Gmpq> > > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&);
|
||||
#endif
|
||||
466
src/igl/copyleft/cgal/mesh_boolean.cpp
Normal file
466
src/igl/copyleft/cgal/mesh_boolean.cpp
Normal file
|
|
@ -0,0 +1,466 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
// 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 "mesh_boolean.h"
|
||||
#include "assign.h"
|
||||
#include "extract_cells.h"
|
||||
#include "mesh_boolean_type_to_funcs.h"
|
||||
#include "propagate_winding_numbers.h"
|
||||
#include "relabel_small_immersed_cells.h"
|
||||
#include "remesh_self_intersections.h"
|
||||
#include "string_to_mesh_boolean_type.h"
|
||||
#include "../../combine.h"
|
||||
#include "../../cumsum.h"
|
||||
#include "../../extract_manifold_patches.h"
|
||||
#include "../../get_seconds.h"
|
||||
#include "../../remove_unreferenced.h"
|
||||
#include "../../resolve_duplicated_faces.h"
|
||||
#include "../../slice.h"
|
||||
#include "../../unique_edge_map.h"
|
||||
#include "../../unique_simplices.h"
|
||||
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <algorithm>
|
||||
|
||||
//#define MESH_BOOLEAN_TIMING
|
||||
//#define DOUBLE_CHECK_EXACT_OUTPUT
|
||||
//#define SMALL_CELL_REMOVAL
|
||||
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
|
||||
const Eigen::MatrixBase<DerivedVA > & VA,
|
||||
const Eigen::MatrixBase<DerivedFA > & FA,
|
||||
const Eigen::MatrixBase<DerivedVB > & VB,
|
||||
const Eigen::MatrixBase<DerivedFB > & FB,
|
||||
const MeshBooleanType & type,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J)
|
||||
{
|
||||
std::function<int(const int, const int)> keep;
|
||||
std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) > wind_num_op;
|
||||
mesh_boolean_type_to_funcs(type,wind_num_op,keep);
|
||||
return mesh_boolean(VA,FA,VB,FB,wind_num_op,keep,VC,FC,J);
|
||||
}
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
|
||||
const Eigen::MatrixBase<DerivedVA > & VA,
|
||||
const Eigen::MatrixBase<DerivedFA > & FA,
|
||||
const Eigen::MatrixBase<DerivedVB > & VB,
|
||||
const Eigen::MatrixBase<DerivedFB > & FB,
|
||||
const std::string & type_str,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J)
|
||||
{
|
||||
return mesh_boolean(
|
||||
VA,FA,VB,FB,string_to_mesh_boolean_type(type_str),VC,FC,J);
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
|
||||
const Eigen::MatrixBase<DerivedVA> & VA,
|
||||
const Eigen::MatrixBase<DerivedFA> & FA,
|
||||
const Eigen::MatrixBase<DerivedVB> & VB,
|
||||
const Eigen::MatrixBase<DerivedFB> & FB,
|
||||
const std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >& wind_num_op,
|
||||
const std::function<int(const int, const int)> & keep,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J)
|
||||
{
|
||||
// Generate combined mesh (VA,FA,VB,FB) -> (V,F)
|
||||
Eigen::Matrix<size_t,2,1> sizes(FA.rows(),FB.rows());
|
||||
// TODO: This is a precision template **bug** that results in failure to
|
||||
// compile. If DerivedVA::Scalar is double and DerivedVB::Scalar is
|
||||
// CGAL::Epeck::FT then the following assignment will not compile. This
|
||||
// implies that VA must have the trumping precision (and a valid assignment
|
||||
// operator from VB's type).
|
||||
Eigen::Matrix<typename DerivedVA::Scalar,Eigen::Dynamic,3> VV(VA.rows() + VB.rows(), 3);
|
||||
DerivedFC FF(FA.rows() + FB.rows(), 3);
|
||||
// Can't use comma initializer
|
||||
for(int a = 0;a<VA.rows();a++)
|
||||
{
|
||||
for(int d = 0;d<3;d++) VV(a,d) = VA(a,d);
|
||||
}
|
||||
for(int b = 0;b<VB.rows();b++)
|
||||
{
|
||||
for(int d = 0;d<3;d++) VV(VA.rows()+b,d) = VB(b,d);
|
||||
}
|
||||
FF.block(0, 0, FA.rows(), 3) = FA;
|
||||
// Eigen struggles to assign nothing to nothing and will assert if FB is empty
|
||||
if(FB.rows() > 0)
|
||||
{
|
||||
FF.block(FA.rows(), 0, FB.rows(), 3) = FB.array() + VA.rows();
|
||||
}
|
||||
return mesh_boolean(VV,FF,sizes,wind_num_op,keep,VC,FC,J);
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
|
||||
const std::vector<DerivedV > & Vlist,
|
||||
const std::vector<DerivedF > & Flist,
|
||||
const std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >& wind_num_op,
|
||||
const std::function<int(const int, const int)> & keep,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J)
|
||||
{
|
||||
DerivedV VV;
|
||||
DerivedF FF;
|
||||
Eigen::Matrix<size_t,Eigen::Dynamic,1> Vsizes,Fsizes;
|
||||
igl::combine(Vlist,Flist,VV,FF,Vsizes,Fsizes);
|
||||
return mesh_boolean(VV,FF,Fsizes,wind_num_op,keep,VC,FC,J);
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
|
||||
const std::vector<DerivedV > & Vlist,
|
||||
const std::vector<DerivedF > & Flist,
|
||||
const MeshBooleanType & type,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J)
|
||||
{
|
||||
DerivedV VV;
|
||||
DerivedF FF;
|
||||
Eigen::Matrix<size_t,Eigen::Dynamic,1> Vsizes,Fsizes;
|
||||
igl::combine(Vlist,Flist,VV,FF,Vsizes,Fsizes);
|
||||
std::function<int(const int, const int)> keep;
|
||||
std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) > wind_num_op;
|
||||
mesh_boolean_type_to_funcs(type,wind_num_op,keep);
|
||||
return mesh_boolean(VV,FF,Fsizes,wind_num_op,keep,VC,FC,J);
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename Derivedsizes,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
|
||||
const Eigen::MatrixBase<DerivedVV > & VV,
|
||||
const Eigen::MatrixBase<DerivedFF > & FF,
|
||||
const Eigen::MatrixBase<Derivedsizes> & sizes,
|
||||
const std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >& wind_num_op,
|
||||
const std::function<int(const int, const int)> & keep,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J)
|
||||
{
|
||||
#ifdef MESH_BOOLEAN_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 {
|
||||
std::cout << "mesh_boolean." << label << ": "
|
||||
<< tictoc() << std::endl;
|
||||
};
|
||||
tictoc();
|
||||
#endif
|
||||
typedef typename DerivedVC::Scalar Scalar;
|
||||
typedef CGAL::Epeck Kernel;
|
||||
typedef Kernel::FT ExactScalar;
|
||||
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,3> MatrixX3S;
|
||||
typedef Eigen::Matrix<typename DerivedJ::Scalar,Eigen::Dynamic,1> VectorXJ;
|
||||
typedef Eigen::Matrix<
|
||||
ExactScalar,
|
||||
Eigen::Dynamic,
|
||||
Eigen::Dynamic,
|
||||
DerivedVC::IsRowMajor> MatrixXES;
|
||||
MatrixXES V;
|
||||
DerivedFC F;
|
||||
VectorXJ CJ;
|
||||
{
|
||||
Eigen::VectorXi I;
|
||||
igl::copyleft::cgal::RemeshSelfIntersectionsParam params;
|
||||
params.stitch_all = true;
|
||||
MatrixXES Vr;
|
||||
DerivedFC Fr;
|
||||
Eigen::MatrixXi IF;
|
||||
igl::copyleft::cgal::remesh_self_intersections(
|
||||
VV, FF, params, Vr, Fr, IF, CJ, I);
|
||||
assert(I.size() == Vr.rows());
|
||||
// Merge coinciding vertices into non-manifold vertices.
|
||||
std::for_each(Fr.data(), Fr.data()+Fr.size(),
|
||||
[&I](typename DerivedFC::Scalar& a) { a=I[a]; });
|
||||
// Remove unreferenced vertices.
|
||||
Eigen::VectorXi UIM;
|
||||
igl::remove_unreferenced(Vr, Fr, V, F, UIM);
|
||||
}
|
||||
#ifdef MESH_BOOLEAN_TIMING
|
||||
log_time("resolve_self_intersection");
|
||||
#endif
|
||||
|
||||
// Compute edges of (F) --> (E,uE,EMAP,uE2E)
|
||||
Eigen::MatrixXi E, uE;
|
||||
Eigen::VectorXi EMAP;
|
||||
std::vector<std::vector<size_t> > uE2E;
|
||||
igl::unique_edge_map(F, E, uE, EMAP, uE2E);
|
||||
|
||||
// Compute patches (F,EMAP,uE2E) --> (P)
|
||||
Eigen::VectorXi P;
|
||||
const size_t num_patches = igl::extract_manifold_patches(F, EMAP, uE2E, P);
|
||||
#ifdef MESH_BOOLEAN_TIMING
|
||||
log_time("patch_extraction");
|
||||
#endif
|
||||
|
||||
// Compute cells (V,F,P,E,uE,EMAP) -> (per_patch_cells)
|
||||
Eigen::MatrixXi per_patch_cells;
|
||||
const size_t num_cells =
|
||||
igl::copyleft::cgal::extract_cells(
|
||||
V, F, P, E, uE, uE2E, EMAP, per_patch_cells);
|
||||
#ifdef MESH_BOOLEAN_TIMING
|
||||
log_time("cell_extraction");
|
||||
#endif
|
||||
|
||||
// Compute winding numbers on each side of each facet.
|
||||
const size_t num_faces = F.rows();
|
||||
// W(f,:) --> [w1out,w1in,w2out,w2in, ... wnout,wnint] winding numbers above
|
||||
// and below each face w.r.t. each input mesh, so that W(f,2*i) is the
|
||||
// winding number above face f w.r.t. input i, and W(f,2*i+1) is the winding
|
||||
// number below face f w.r.t. input i.
|
||||
Eigen::MatrixXi W;
|
||||
// labels(f) = i means that face f comes from mesh i
|
||||
Eigen::VectorXi labels(num_faces);
|
||||
// cumulative sizes
|
||||
Derivedsizes cumsizes;
|
||||
igl::cumsum(sizes,1,cumsizes);
|
||||
const size_t num_inputs = sizes.size();
|
||||
std::transform(
|
||||
CJ.data(),
|
||||
CJ.data()+CJ.size(),
|
||||
labels.data(),
|
||||
// Determine which input mesh birth face i comes from
|
||||
[&num_inputs,&cumsizes](int i)->int
|
||||
{
|
||||
for(int k = 0;k<num_inputs;k++)
|
||||
{
|
||||
if(i<cumsizes(k)) return k;
|
||||
}
|
||||
assert(false && "Birth parent index out of range");
|
||||
return -1;
|
||||
});
|
||||
bool valid = true;
|
||||
if (num_faces > 0)
|
||||
{
|
||||
valid = valid &
|
||||
igl::copyleft::cgal::propagate_winding_numbers(
|
||||
V, F, uE, uE2E, num_patches, P, num_cells, per_patch_cells, labels, W);
|
||||
} else
|
||||
{
|
||||
W.resize(0, 2*num_inputs);
|
||||
}
|
||||
assert((size_t)W.rows() == num_faces);
|
||||
// If W doesn't have enough columns, pad with zeros
|
||||
if (W.cols() <= 2*num_inputs)
|
||||
{
|
||||
const int old_ncols = W.cols();
|
||||
W.conservativeResize(num_faces,2*num_inputs);
|
||||
W.rightCols(2*num_inputs-old_ncols).setConstant(0);
|
||||
}
|
||||
assert((size_t)W.cols() == 2*num_inputs);
|
||||
#ifdef MESH_BOOLEAN_TIMING
|
||||
log_time("propagate_input_winding_number");
|
||||
#endif
|
||||
|
||||
// Compute resulting winding number.
|
||||
Eigen::MatrixXi Wr(num_faces, 2);
|
||||
for (size_t i=0; i<num_faces; i++)
|
||||
{
|
||||
// Winding number vectors above and below
|
||||
Eigen::RowVectorXi w_out(1,num_inputs), w_in(1,num_inputs);
|
||||
for(size_t k =0;k<num_inputs;k++)
|
||||
{
|
||||
w_out(k) = W(i,2*k+0);
|
||||
w_in(k) = W(i,2*k+1);
|
||||
}
|
||||
Wr(i,0) = wind_num_op(w_out);
|
||||
Wr(i,1) = wind_num_op(w_in);
|
||||
}
|
||||
#ifdef MESH_BOOLEAN_TIMING
|
||||
log_time("compute_output_winding_number");
|
||||
#endif
|
||||
|
||||
#ifdef SMALL_CELL_REMOVAL
|
||||
igl::copyleft::cgal::relabel_small_immersed_cells(
|
||||
V, F, num_patches, P, num_cells, per_patch_cells, 1e-3, Wr);
|
||||
#endif
|
||||
|
||||
// Extract boundary separating inside from outside.
|
||||
auto index_to_signed_index = [&](size_t i, bool ori) -> int
|
||||
{
|
||||
return (i+1)*(ori?1:-1);
|
||||
};
|
||||
//auto signed_index_to_index = [&](int i) -> size_t {
|
||||
// return abs(i) - 1;
|
||||
//};
|
||||
std::vector<int> selected;
|
||||
for(size_t i=0; i<num_faces; i++)
|
||||
{
|
||||
auto should_keep = keep(Wr(i,0), Wr(i,1));
|
||||
if (should_keep > 0)
|
||||
{
|
||||
selected.push_back(index_to_signed_index(i, true));
|
||||
} else if (should_keep < 0)
|
||||
{
|
||||
selected.push_back(index_to_signed_index(i, false));
|
||||
}
|
||||
}
|
||||
|
||||
const size_t num_selected = selected.size();
|
||||
DerivedFC kept_faces(num_selected, 3);
|
||||
DerivedJ kept_face_indices(num_selected, 1);
|
||||
for (size_t i=0; i<num_selected; i++)
|
||||
{
|
||||
size_t idx = abs(selected[i]) - 1;
|
||||
if (selected[i] > 0)
|
||||
{
|
||||
kept_faces.row(i) = F.row(idx);
|
||||
} else
|
||||
{
|
||||
kept_faces.row(i) = F.row(idx).reverse();
|
||||
}
|
||||
kept_face_indices(i, 0) = CJ[idx];
|
||||
}
|
||||
#ifdef MESH_BOOLEAN_TIMING
|
||||
log_time("extract_output");
|
||||
#endif
|
||||
|
||||
// Finally, remove duplicated faces and unreferenced vertices.
|
||||
{
|
||||
DerivedFC G;
|
||||
DerivedJ JJ;
|
||||
igl::resolve_duplicated_faces(kept_faces, G, JJ);
|
||||
igl::slice(kept_face_indices, JJ, 1, J);
|
||||
|
||||
#ifdef DOUBLE_CHECK_EXACT_OUTPUT
|
||||
{
|
||||
// Sanity check on exact output.
|
||||
igl::copyleft::cgal::RemeshSelfIntersectionsParam params;
|
||||
params.detect_only = true;
|
||||
params.first_only = true;
|
||||
MatrixXES dummy_VV;
|
||||
DerivedFC dummy_FF, dummy_IF;
|
||||
Eigen::VectorXi dummy_J, dummy_IM;
|
||||
igl::copyleft::cgal::SelfIntersectMesh<
|
||||
Kernel,
|
||||
MatrixXES, DerivedFC,
|
||||
MatrixXES, DerivedFC,
|
||||
DerivedFC,
|
||||
Eigen::VectorXi,
|
||||
Eigen::VectorXi
|
||||
> checker(V, G, params,
|
||||
dummy_VV, dummy_FF, dummy_IF, dummy_J, dummy_IM);
|
||||
if (checker.count != 0)
|
||||
{
|
||||
throw "Self-intersection not fully resolved.";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
MatrixX3S Vs;
|
||||
assign(V,Vs);
|
||||
Eigen::VectorXi newIM;
|
||||
igl::remove_unreferenced(Vs,G,VC,FC,newIM);
|
||||
}
|
||||
#ifdef MESH_BOOLEAN_TIMING
|
||||
log_time("clean_up");
|
||||
#endif
|
||||
return valid;
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC>
|
||||
IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
|
||||
const Eigen::MatrixBase<DerivedVA > & VA,
|
||||
const Eigen::MatrixBase<DerivedFA > & FA,
|
||||
const Eigen::MatrixBase<DerivedVB > & VB,
|
||||
const Eigen::MatrixBase<DerivedFB > & FB,
|
||||
const MeshBooleanType & type,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedFC::Index, Eigen::Dynamic,1> J;
|
||||
return igl::copyleft::cgal::mesh_boolean(VA,FA,VB,FB,type,VC,FC,J);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, 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 bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, 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 bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -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>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, 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 bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 4, 0, -1, 4>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 4, 0, -1, 4>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 4, 0, -1, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 4, 0, -1, 4> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<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::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<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<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::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&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType 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<int, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<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::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&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > 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<int, -1, -1, 0, -1, -1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<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::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&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > 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<int, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, 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<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > 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&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3>, 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<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType 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<int, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<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::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&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType 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<int, -1, -1, 0, -1, -1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<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<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&, std::function<int (Eigen::Matrix<int, 1, -1, 1, 1, -1>)> const&, std::function<int (int, int)> 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<int, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<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<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&, igl::MeshBooleanType 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<int, -1, 1, 0, -1, 1> >&);
|
||||
#ifdef WIN32
|
||||
template bool igl::copyleft::cgal::mesh_boolean<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::MatrixBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> const &, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::MatrixBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> const &, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, enum igl::MeshBooleanType const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
|
||||
#endif
|
||||
#endif
|
||||
229
src/igl/copyleft/cgal/mesh_boolean.h
Normal file
229
src/igl/copyleft/cgal/mesh_boolean.h
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
// 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_MESH_BOOLEAN_H
|
||||
#define IGL_COPYLEFT_CGAL_MESH_BOOLEAN_H
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
#include "../../MeshBooleanType.h"
|
||||
#include <Eigen/Core>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// MESH_BOOLEAN Compute boolean csg operations on "solid", consistently
|
||||
// oriented meshes.
|
||||
//
|
||||
// Inputs:
|
||||
// VA #VA by 3 list of vertex positions of first mesh
|
||||
// FA #FA by 3 list of triangle indices into VA
|
||||
// VB #VB by 3 list of vertex positions of second mesh
|
||||
// FB #FB by 3 list of triangle indices into VB
|
||||
// type type of boolean operation
|
||||
// Outputs:
|
||||
// VC #VC by 3 list of vertex positions of boolean result mesh
|
||||
// FC #FC by 3 list of triangle indices into VC
|
||||
// J #FC list of indices into [FA;FA.rows()+FB] revealing "birth" facet
|
||||
// Returns true if inputs induce a piecewise constant winding number
|
||||
// field and type is valid
|
||||
//
|
||||
// See also: mesh_boolean_cork, intersect_other,
|
||||
// remesh_self_intersections
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool mesh_boolean(
|
||||
const Eigen::MatrixBase<DerivedVA > & VA,
|
||||
const Eigen::MatrixBase<DerivedFA > & FA,
|
||||
const Eigen::MatrixBase<DerivedVB > & VB,
|
||||
const Eigen::MatrixBase<DerivedFB > & FB,
|
||||
const MeshBooleanType & type,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J);
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool mesh_boolean(
|
||||
const Eigen::MatrixBase<DerivedVA > & VA,
|
||||
const Eigen::MatrixBase<DerivedFA > & FA,
|
||||
const Eigen::MatrixBase<DerivedVB > & VB,
|
||||
const Eigen::MatrixBase<DerivedFB > & FB,
|
||||
const std::string & type_str,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J);
|
||||
//
|
||||
// Inputs:
|
||||
// VA #VA by 3 list of vertex positions of first mesh
|
||||
// FA #FA by 3 list of triangle indices into VA
|
||||
// VB #VB by 3 list of vertex positions of second mesh
|
||||
// FB #FB by 3 list of triangle indices into VB
|
||||
// wind_num_op function handle for filtering winding numbers from
|
||||
// tuples of integer values to [0,1] outside/inside values
|
||||
// keep function handle for determining if a patch should be "kept"
|
||||
// in the output based on the winding number on either side
|
||||
// Outputs:
|
||||
// VC #VC by 3 list of vertex positions of boolean result mesh
|
||||
// FC #FC by 3 list of triangle indices into VC
|
||||
// J #FC list of indices into [FA;FB] revealing "birth" facet
|
||||
// Returns true iff inputs induce a piecewise constant winding number
|
||||
// field
|
||||
//
|
||||
// See also: mesh_boolean_cork, intersect_other,
|
||||
// remesh_self_intersections
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool mesh_boolean(
|
||||
const Eigen::MatrixBase<DerivedVA> & VA,
|
||||
const Eigen::MatrixBase<DerivedFA> & FA,
|
||||
const Eigen::MatrixBase<DerivedVB> & VB,
|
||||
const Eigen::MatrixBase<DerivedFB> & FB,
|
||||
const std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >& wind_num_op,
|
||||
const std::function<int(const int, const int)> & keep,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J);
|
||||
// MESH_BOOLEAN Variadic boolean operations
|
||||
//
|
||||
// Inputs:
|
||||
// Vlist k-long list of lists of mesh vertex positions
|
||||
// Flist k-long list of lists of mesh face indices, so that Flist[i] indexes
|
||||
// vertices in Vlist[i]
|
||||
// wind_num_op function handle for filtering winding numbers from
|
||||
// n-tuples of integer values to [0,1] outside/inside values
|
||||
// keep function handle for determining if a patch should be "kept"
|
||||
// in the output based on the winding number on either side
|
||||
// Outputs:
|
||||
// VC #VC by 3 list of vertex positions of boolean result mesh
|
||||
// FC #FC by 3 list of triangle indices into VC
|
||||
// J #FC list of indices into [Flist[0];Flist[1];...;Flist[k]]
|
||||
// revealing "birth" facet
|
||||
// Returns true iff inputs induce a piecewise constant winding number
|
||||
// field
|
||||
//
|
||||
// See also: mesh_boolean_cork, intersect_other,
|
||||
// remesh_self_intersections
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool mesh_boolean(
|
||||
const std::vector<DerivedV > & Vlist,
|
||||
const std::vector<DerivedF > & Flist,
|
||||
const std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >& wind_num_op,
|
||||
const std::function<int(const int, const int)> & keep,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J);
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool mesh_boolean(
|
||||
const std::vector<DerivedV > & Vlist,
|
||||
const std::vector<DerivedF > & Flist,
|
||||
const MeshBooleanType & type,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J);
|
||||
// Given a merged mesh (V,F) and list of sizes of inputs
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of merged mesh vertex positions
|
||||
// F #F by 3 list of merged mesh face indices so that first sizes(0)
|
||||
// faces come from the first input, and the next sizes(1) faces come
|
||||
// from the second input, and so on.
|
||||
// sizes #inputs list of sizes so that sizes(i) is the #faces in the
|
||||
// ith input
|
||||
// wind_num_op function handle for filtering winding numbers from
|
||||
// tuples of integer values to [0,1] outside/inside values
|
||||
// keep function handle for determining if a patch should be "kept"
|
||||
// in the output based on the winding number on either side
|
||||
// Outputs:
|
||||
// VC #VC by 3 list of vertex positions of boolean result mesh
|
||||
// FC #FC by 3 list of triangle indices into VC
|
||||
// J #FC list of birth parent indices
|
||||
//
|
||||
template <
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename Derivedsizes,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool mesh_boolean(
|
||||
const Eigen::MatrixBase<DerivedVV > & VV,
|
||||
const Eigen::MatrixBase<DerivedFF > & FF,
|
||||
const Eigen::MatrixBase<Derivedsizes> & sizes,
|
||||
const std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >& wind_num_op,
|
||||
const std::function<int(const int, const int)> & keep,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J);
|
||||
// Inputs:
|
||||
// VA #VA by 3 list of vertex positions of first mesh
|
||||
// FA #FA by 3 list of triangle indices into VA
|
||||
// VB #VB by 3 list of vertex positions of second mesh
|
||||
// FB #FB by 3 list of triangle indices into VB
|
||||
// type type of boolean operation
|
||||
// Outputs:
|
||||
// VC #VC by 3 list of vertex positions of boolean result mesh
|
||||
// FC #FC by 3 list of triangle indices into VC
|
||||
// Returns true ff inputs induce a piecewise constant winding number
|
||||
// field and type is valid
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC>
|
||||
IGL_INLINE bool mesh_boolean(
|
||||
const Eigen::MatrixBase<DerivedVA > & VA,
|
||||
const Eigen::MatrixBase<DerivedFA > & FA,
|
||||
const Eigen::MatrixBase<DerivedVB > & VB,
|
||||
const Eigen::MatrixBase<DerivedFB > & FB,
|
||||
const MeshBooleanType & type,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "mesh_boolean.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
39
src/igl/copyleft/cgal/mesh_boolean_type_to_funcs.cpp
Normal file
39
src/igl/copyleft/cgal/mesh_boolean_type_to_funcs.cpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#include "mesh_boolean_type_to_funcs.h"
|
||||
#include "BinaryWindingNumberOperations.h"
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::mesh_boolean_type_to_funcs(
|
||||
const MeshBooleanType & type,
|
||||
std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >& wind_num_op,
|
||||
std::function<int(const int, const int)> & keep)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MESH_BOOLEAN_TYPE_UNION:
|
||||
wind_num_op = BinaryUnion();
|
||||
keep = KeepInside();
|
||||
return;
|
||||
case MESH_BOOLEAN_TYPE_INTERSECT:
|
||||
wind_num_op = BinaryIntersect();
|
||||
keep = KeepInside();
|
||||
return;
|
||||
case MESH_BOOLEAN_TYPE_MINUS:
|
||||
wind_num_op = BinaryMinus();
|
||||
keep = KeepInside();
|
||||
return;
|
||||
case MESH_BOOLEAN_TYPE_XOR:
|
||||
wind_num_op = BinaryXor();
|
||||
keep = KeepInside();
|
||||
return;
|
||||
case MESH_BOOLEAN_TYPE_RESOLVE:
|
||||
wind_num_op = BinaryResolve();
|
||||
keep = KeepAll();
|
||||
return;
|
||||
default:
|
||||
assert(false && "Unsupported boolean type.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
#endif
|
||||
37
src/igl/copyleft/cgal/mesh_boolean_type_to_funcs.h
Normal file
37
src/igl/copyleft/cgal/mesh_boolean_type_to_funcs.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef IGL_COPYLEFT_CGAL_MESH_BOOLEAN_TYPE_TO_FUNCS_H
|
||||
#define IGL_COPYLEFT_CGAL_MESH_BOOLEAN_TYPE_TO_FUNCS_H
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
#include "../../MeshBooleanType.h"
|
||||
#include <Eigen/Core>
|
||||
#include <functional>
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Convert a MeshBooleanType enum to a pair of winding number conversion
|
||||
// function and "keep" function used by mesh_boolean
|
||||
//
|
||||
// Inputs:
|
||||
// type MeshBooleanType enum value
|
||||
// Outputs:
|
||||
// wind_num_op function handle for filtering winding numbers from
|
||||
// tuples of integer values to [0,1] outside/inside values
|
||||
// keep function handle for determining if a patch should be "kept"
|
||||
// in the output based on the winding number on either side
|
||||
//
|
||||
// See also: string_to_mesh_boolean_type
|
||||
IGL_INLINE void mesh_boolean_type_to_funcs(
|
||||
const MeshBooleanType & type,
|
||||
std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >&
|
||||
wind_num_op,
|
||||
std::function<int(const int, const int)> & keep);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "mesh_boolean_type_to_funcs.cpp"
|
||||
#endif
|
||||
#endif
|
||||
76
src/igl/copyleft/cgal/mesh_to_cgal_triangle_list.cpp
Normal file
76
src/igl/copyleft/cgal/mesh_to_cgal_triangle_list.cpp
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
// 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 "mesh_to_cgal_triangle_list.h"
|
||||
#include "assign.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename Kernel>
|
||||
IGL_INLINE void igl::copyleft::cgal::mesh_to_cgal_triangle_list(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
std::vector<CGAL::Triangle_3<Kernel> > & T)
|
||||
{
|
||||
typedef CGAL::Point_3<Kernel> Point_3;
|
||||
typedef CGAL::Triangle_3<Kernel> Triangle_3;
|
||||
// Must be 3D
|
||||
assert(V.cols() == 3);
|
||||
// **Copy** to convert to output type (this is especially/only needed if the
|
||||
// input type DerivedV::Scalar is CGAL::Epeck
|
||||
Eigen::Matrix<
|
||||
typename Kernel::FT,
|
||||
DerivedV::RowsAtCompileTime,
|
||||
DerivedV::ColsAtCompileTime>
|
||||
KV(V.rows(),V.cols());
|
||||
assign(V,KV);
|
||||
// Must be triangles
|
||||
assert(F.cols() == 3);
|
||||
T.reserve(F.rows());
|
||||
// Loop over faces
|
||||
for(int f = 0;f<(int)F.rows();f++)
|
||||
{
|
||||
T.push_back(
|
||||
Triangle_3(
|
||||
Point_3( KV(F(f,0),0), KV(F(f,0),1), KV(F(f,0),2)),
|
||||
Point_3( KV(F(f,1),0), KV(F(f,1),1), KV(F(f,1),2)),
|
||||
Point_3( KV(F(f,2),0), KV(F(f,2),1), KV(F(f,2),2))));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
|
||||
#endif
|
||||
44
src/igl/copyleft/cgal/mesh_to_cgal_triangle_list.h
Normal file
44
src/igl/copyleft/cgal/mesh_to_cgal_triangle_list.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// 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_MESH_TO_CGAL_TRIANGLE_LIST_H
|
||||
#define IGL_COPYLEFT_CGAL_MESH_TO_CGAL_TRIANGLE_LIST_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include "CGAL_includes.hpp"
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Convert a mesh (V,F) to a list of CGAL triangles
|
||||
//
|
||||
// Templates:
|
||||
// Kernal CGAL computation and construction kernel (e.g.
|
||||
// CGAL::Exact_predicates_exact_constructions_kernel)
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices
|
||||
// Outputs:
|
||||
// T #F list of CGAL triangles
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename Kernel>
|
||||
IGL_INLINE void mesh_to_cgal_triangle_list(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
std::vector<CGAL::Triangle_3<Kernel> > & T);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "mesh_to_cgal_triangle_list.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
54
src/igl/copyleft/cgal/mesh_to_polyhedron.cpp
Normal file
54
src/igl/copyleft/cgal/mesh_to_polyhedron.cpp
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// 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 "mesh_to_polyhedron.h"
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
#include <CGAL/Polyhedron_incremental_builder_3.h>
|
||||
|
||||
|
||||
template <typename Polyhedron>
|
||||
IGL_INLINE bool igl::copyleft::cgal::mesh_to_polyhedron(
|
||||
const Eigen::MatrixXd & V,
|
||||
const Eigen::MatrixXi & F,
|
||||
Polyhedron & poly)
|
||||
{
|
||||
typedef typename Polyhedron::HalfedgeDS HalfedgeDS;
|
||||
// Postcondition: hds is a valid polyhedral surface.
|
||||
CGAL::Polyhedron_incremental_builder_3<HalfedgeDS> B(poly.hds());
|
||||
B.begin_surface(V.rows(),F.rows());
|
||||
typedef typename HalfedgeDS::Vertex Vertex;
|
||||
typedef typename Vertex::Point Point;
|
||||
assert(V.cols() == 3 && "V must be #V by 3");
|
||||
for(int v = 0;v<V.rows();v++)
|
||||
{
|
||||
B.add_vertex(Point(V(v,0),V(v,1),V(v,2)));
|
||||
}
|
||||
assert(F.cols() == 3 && "F must be #F by 3");
|
||||
for(int f=0;f<F.rows();f++)
|
||||
{
|
||||
B.begin_facet();
|
||||
for(int c = 0;c<3;c++)
|
||||
{
|
||||
B.add_vertex_to_facet(F(f,c));
|
||||
}
|
||||
B.end_facet();
|
||||
}
|
||||
if(B.error())
|
||||
{
|
||||
B.rollback();
|
||||
return false;
|
||||
}
|
||||
B.end_surface();
|
||||
return poly.is_valid();
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Polyhedron_items_with_id_3.h>
|
||||
template bool igl::copyleft::cgal::mesh_to_polyhedron<CGAL::Polyhedron_3<CGAL::Simple_cartesian<double>, CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator<int> > >(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, CGAL::Polyhedron_3<CGAL::Simple_cartesian<double>, CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator<int> >&);
|
||||
#endif
|
||||
42
src/igl/copyleft/cgal/mesh_to_polyhedron.h
Normal file
42
src/igl/copyleft/cgal/mesh_to_polyhedron.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// 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_MESH_TO_POLYHEDRON_H
|
||||
#define IGL_COPYLEFT_CGAL_MESH_TO_POLYHEDRON_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Convert a mesh (V,F) to a CGAL Polyhedron
|
||||
//
|
||||
// Templates:
|
||||
// Polyhedron CGAL Polyhedron type (e.g. Polyhedron_3)
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices
|
||||
// Outputs:
|
||||
// poly cgal polyhedron
|
||||
// Returns true only if (V,F) can be converted to a valid polyhedron (i.e. if
|
||||
// (V,F) is vertex and edge manifold).
|
||||
template <typename Polyhedron>
|
||||
IGL_INLINE bool mesh_to_polyhedron(
|
||||
const Eigen::MatrixXd & V,
|
||||
const Eigen::MatrixXi & F,
|
||||
Polyhedron & poly);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "mesh_to_polyhedron.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
395
src/igl/copyleft/cgal/minkowski_sum.cpp
Normal file
395
src/igl/copyleft/cgal/minkowski_sum.cpp
Normal file
|
|
@ -0,0 +1,395 @@
|
|||
// 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 "minkowski_sum.h"
|
||||
#include "mesh_boolean.h"
|
||||
|
||||
#include "../../slice.h"
|
||||
#include "../../slice_mask.h"
|
||||
#include "../../LinSpaced.h"
|
||||
#include "../../unique_rows.h"
|
||||
#include "../../get_seconds.h"
|
||||
#include "../../edges.h"
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedW,
|
||||
typename DerivedG,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE void igl::copyleft::cgal::minkowski_sum(
|
||||
const Eigen::MatrixBase<DerivedVA> & VA,
|
||||
const Eigen::MatrixBase<DerivedFA> & FA,
|
||||
const Eigen::MatrixBase<DerivedVB> & VB,
|
||||
const Eigen::MatrixBase<DerivedFB> & FB,
|
||||
const bool resolve_overlaps,
|
||||
Eigen::PlainObjectBase<DerivedW> & W,
|
||||
Eigen::PlainObjectBase<DerivedG> & G,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
assert(FA.cols() == 3 && "FA must contain a closed triangle mesh");
|
||||
assert(FB.cols() <= FA.cols() &&
|
||||
"FB must contain lower diemnsional simplices than FA");
|
||||
const auto tictoc = []()->double
|
||||
{
|
||||
static double t_start;
|
||||
double now = igl::get_seconds();
|
||||
double interval = now-t_start;
|
||||
t_start = now;
|
||||
return interval;
|
||||
};
|
||||
tictoc();
|
||||
Matrix<typename DerivedFB::Scalar,Dynamic,2> EB;
|
||||
edges(FB,EB);
|
||||
Matrix<typename DerivedFA::Scalar,Dynamic,2> EA(0,2);
|
||||
if(FB.cols() == 3)
|
||||
{
|
||||
edges(FA,EA);
|
||||
}
|
||||
// number of copies of A along edges of B
|
||||
const int n_ab = EB.rows();
|
||||
// number of copies of B along edges of A
|
||||
const int n_ba = EA.rows();
|
||||
|
||||
vector<DerivedW> vW(n_ab + n_ba);
|
||||
vector<DerivedG> vG(n_ab + n_ba);
|
||||
vector<DerivedJ> vJ(n_ab + n_ba);
|
||||
vector<int> offsets(n_ab + n_ba + 1);
|
||||
offsets[0] = 0;
|
||||
// sweep A along edges of B
|
||||
for(int e = 0;e<n_ab;e++)
|
||||
{
|
||||
Matrix<typename DerivedJ::Scalar,Dynamic,1> eJ;
|
||||
minkowski_sum(
|
||||
VA,
|
||||
FA,
|
||||
VB.row(EB(e,0)).eval(),
|
||||
VB.row(EB(e,1)).eval(),
|
||||
false,
|
||||
vW[e],
|
||||
vG[e],
|
||||
eJ);
|
||||
assert(vG[e].rows() == eJ.rows());
|
||||
assert(eJ.cols() == 1);
|
||||
vJ[e].resize(vG[e].rows(),2);
|
||||
vJ[e].col(0) = eJ;
|
||||
vJ[e].col(1).setConstant(e);
|
||||
offsets[e+1] = offsets[e] + vW[e].rows();
|
||||
}
|
||||
// sweep B along edges of A
|
||||
for(int e = 0;e<n_ba;e++)
|
||||
{
|
||||
Matrix<typename DerivedJ::Scalar,Dynamic,1> eJ;
|
||||
const int ee = n_ab+e;
|
||||
minkowski_sum(
|
||||
VB,
|
||||
FB,
|
||||
VA.row(EA(e,0)).eval(),
|
||||
VA.row(EA(e,1)).eval(),
|
||||
false,
|
||||
vW[ee],
|
||||
vG[ee],
|
||||
eJ);
|
||||
vJ[ee].resize(vG[ee].rows(),2);
|
||||
vJ[ee].col(0) = eJ.array() + (FA.rows()+1);
|
||||
vJ[ee].col(1).setConstant(ee);
|
||||
offsets[ee+1] = offsets[ee] + vW[ee].rows();
|
||||
}
|
||||
// Combine meshes
|
||||
int n=0,m=0;
|
||||
for_each(vW.begin(),vW.end(),[&n](const DerivedW & w){n+=w.rows();});
|
||||
for_each(vG.begin(),vG.end(),[&m](const DerivedG & g){m+=g.rows();});
|
||||
assert(n == offsets.back());
|
||||
|
||||
W.resize(n,3);
|
||||
G.resize(m,3);
|
||||
J.resize(m,2);
|
||||
{
|
||||
int m_off = 0,n_off = 0;
|
||||
for(int i = 0;i<vG.size();i++)
|
||||
{
|
||||
W.block(n_off,0,vW[i].rows(),3) = vW[i];
|
||||
G.block(m_off,0,vG[i].rows(),3) = vG[i].array()+offsets[i];
|
||||
J.block(m_off,0,vJ[i].rows(),2) = vJ[i];
|
||||
n_off += vW[i].rows();
|
||||
m_off += vG[i].rows();
|
||||
}
|
||||
assert(n == n_off);
|
||||
assert(m == m_off);
|
||||
}
|
||||
if(resolve_overlaps)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedJ::Scalar, Eigen::Dynamic,1> SJ;
|
||||
mesh_boolean(
|
||||
DerivedW(W),
|
||||
DerivedG(G),
|
||||
Matrix<typename DerivedW::Scalar,Dynamic,Dynamic>(),
|
||||
Matrix<typename DerivedG::Scalar,Dynamic,Dynamic>(),
|
||||
MESH_BOOLEAN_TYPE_UNION,
|
||||
W,
|
||||
G,
|
||||
SJ);
|
||||
slice(DerivedJ(J),SJ,1,J);
|
||||
}
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename sType, int sCols, int sOptions,
|
||||
typename dType, int dCols, int dOptions,
|
||||
typename DerivedW,
|
||||
typename DerivedG,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE void igl::copyleft::cgal::minkowski_sum(
|
||||
const Eigen::MatrixBase<DerivedVA> & VA,
|
||||
const Eigen::MatrixBase<DerivedFA> & FA,
|
||||
const Eigen::Matrix<sType,1,sCols,sOptions> & s,
|
||||
const Eigen::Matrix<dType,1,dCols,dOptions> & d,
|
||||
const bool resolve_overlaps,
|
||||
Eigen::PlainObjectBase<DerivedW> & W,
|
||||
Eigen::PlainObjectBase<DerivedG> & G,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J)
|
||||
{
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
assert(s.cols() == 3 && "s should be a 3d point");
|
||||
assert(d.cols() == 3 && "d should be a 3d point");
|
||||
// silly base case
|
||||
if(FA.size() == 0)
|
||||
{
|
||||
W.resize(0,3);
|
||||
G.resize(0,3);
|
||||
return;
|
||||
}
|
||||
const int dim = VA.cols();
|
||||
assert(dim == 3 && "dim must be 3D");
|
||||
assert(s.size() == 3 && "s must be 3D point");
|
||||
assert(d.size() == 3 && "d must be 3D point");
|
||||
// segment vector
|
||||
const CGAL::Vector_3<CGAL::Epeck> v(d(0)-s(0),d(1)-s(1),d(2)-s(2));
|
||||
// number of vertices
|
||||
const int n = VA.rows();
|
||||
// duplicate vertices at s and d, we'll remove unreferernced later
|
||||
W.resize(2*n,dim);
|
||||
for(int i = 0;i<n;i++)
|
||||
{
|
||||
for(int j = 0;j<dim;j++)
|
||||
{
|
||||
W (i,j) = VA(i,j) + s(j);
|
||||
W(i+n,j) = VA(i,j) + d(j);
|
||||
}
|
||||
}
|
||||
// number of faces
|
||||
const int m = FA.rows();
|
||||
//// Mask whether positive dot product, or negative: because of exactly zero,
|
||||
//// these are not necessarily complementary
|
||||
// Nevermind, actually P = !N
|
||||
Matrix<bool,Dynamic,1> P(m,1),N(m,1);
|
||||
// loop over faces
|
||||
int mp = 0,mn = 0;
|
||||
for(int f = 0;f<m;f++)
|
||||
{
|
||||
const CGAL::Plane_3<CGAL::Epeck> plane(
|
||||
CGAL::Point_3<CGAL::Epeck>(VA(FA(f,0),0),VA(FA(f,0),1),VA(FA(f,0),2)),
|
||||
CGAL::Point_3<CGAL::Epeck>(VA(FA(f,1),0),VA(FA(f,1),1),VA(FA(f,1),2)),
|
||||
CGAL::Point_3<CGAL::Epeck>(VA(FA(f,2),0),VA(FA(f,2),1),VA(FA(f,2),2)));
|
||||
const auto normal = plane.orthogonal_vector();
|
||||
const auto dt = normal * v;
|
||||
if(dt > 0)
|
||||
{
|
||||
P(f) = true;
|
||||
N(f) = false;
|
||||
mp++;
|
||||
}else
|
||||
//}else if(dt < 0)
|
||||
{
|
||||
P(f) = false;
|
||||
N(f) = true;
|
||||
mn++;
|
||||
//}else
|
||||
//{
|
||||
// P(f) = false;
|
||||
// N(f) = false;
|
||||
}
|
||||
}
|
||||
|
||||
typedef Matrix<typename DerivedG::Scalar,Dynamic,Dynamic> MatrixXI;
|
||||
typedef Matrix<typename DerivedG::Scalar,Dynamic,1> VectorXI;
|
||||
MatrixXI GT(mp+mn,3);
|
||||
GT<< slice_mask(FA,N,1), slice_mask((FA.array()+n).eval(),P,1);
|
||||
// J indexes FA for parts at s and m+FA for parts at d
|
||||
J.derived() = igl::LinSpaced<DerivedJ >(m,0,m-1);
|
||||
DerivedJ JT(mp+mn);
|
||||
JT << slice_mask(J,P,1), slice_mask(J,N,1);
|
||||
JT.block(mp,0,mn,1).array()+=m;
|
||||
|
||||
// Original non-co-planar faces with positively oriented reversed
|
||||
MatrixXI BA(mp+mn,3);
|
||||
BA << slice_mask(FA,P,1).rowwise().reverse(), slice_mask(FA,N,1);
|
||||
// Quads along **all** sides
|
||||
MatrixXI GQ((mp+mn)*3,4);
|
||||
GQ<<
|
||||
BA.col(1), BA.col(0), BA.col(0).array()+n, BA.col(1).array()+n,
|
||||
BA.col(2), BA.col(1), BA.col(1).array()+n, BA.col(2).array()+n,
|
||||
BA.col(0), BA.col(2), BA.col(2).array()+n, BA.col(0).array()+n;
|
||||
|
||||
MatrixXI uGQ;
|
||||
VectorXI S,sI,sJ;
|
||||
// Inputs:
|
||||
// F #F by d list of polygons
|
||||
// Outputs:
|
||||
// S #uF list of signed incidences for each unique face
|
||||
// uF #uF by d list of unique faces
|
||||
// I #uF index vector so that uF = sort(F,2)(I,:)
|
||||
// J #F index vector so that sort(F,2) = uF(J,:)
|
||||
[](
|
||||
const MatrixXI & F,
|
||||
VectorXI & S,
|
||||
MatrixXI & uF,
|
||||
VectorXI & I,
|
||||
VectorXI & J)
|
||||
{
|
||||
const int m = F.rows();
|
||||
const int d = F.cols();
|
||||
MatrixXI sF = F;
|
||||
const auto MN = sF.rowwise().minCoeff().eval();
|
||||
// rotate until smallest index is first
|
||||
for(int p = 0;p<d;p++)
|
||||
{
|
||||
for(int f = 0;f<m;f++)
|
||||
{
|
||||
if(sF(f,0) != MN(f))
|
||||
{
|
||||
for(int r = 0;r<d-1;r++)
|
||||
{
|
||||
std::swap(sF(f,r),sF(f,r+1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// swap orienation so that last index is greater than first
|
||||
for(int f = 0;f<m;f++)
|
||||
{
|
||||
if(sF(f,d-1) < sF(f,1))
|
||||
{
|
||||
sF.block(f,1,1,d-1) = sF.block(f,1,1,d-1).reverse().eval();
|
||||
}
|
||||
}
|
||||
Matrix<bool,Dynamic,1> M = Matrix<bool,Dynamic,1>::Zero(m,1);
|
||||
{
|
||||
VectorXI P = igl::LinSpaced<VectorXI >(d,0,d-1);
|
||||
for(int p = 0;p<d;p++)
|
||||
{
|
||||
for(int f = 0;f<m;f++)
|
||||
{
|
||||
bool all = true;
|
||||
for(int r = 0;r<d;r++)
|
||||
{
|
||||
all = all && (sF(f,P(r)) == F(f,r));
|
||||
}
|
||||
M(f) = M(f) || all;
|
||||
}
|
||||
for(int r = 0;r<d-1;r++)
|
||||
{
|
||||
std::swap(P(r),P(r+1));
|
||||
}
|
||||
}
|
||||
}
|
||||
unique_rows(sF,uF,I,J);
|
||||
S = VectorXI::Zero(uF.rows(),1);
|
||||
assert(m == J.rows());
|
||||
for(int f = 0;f<m;f++)
|
||||
{
|
||||
S(J(f)) += M(f) ? 1 : -1;
|
||||
}
|
||||
}(MatrixXI(GQ),S,uGQ,sI,sJ);
|
||||
assert(S.rows() == uGQ.rows());
|
||||
const int nq = (S.array().abs()==2).count();
|
||||
GQ.resize(nq,4);
|
||||
{
|
||||
int k = 0;
|
||||
for(int q = 0;q<uGQ.rows();q++)
|
||||
{
|
||||
switch(S(q))
|
||||
{
|
||||
case -2:
|
||||
GQ.row(k++) = uGQ.row(q).reverse().eval();
|
||||
break;
|
||||
case 2:
|
||||
GQ.row(k++) = uGQ.row(q);
|
||||
break;
|
||||
default:
|
||||
// do not add
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(nq == k);
|
||||
}
|
||||
|
||||
G.resize(GT.rows()+2*GQ.rows(),3);
|
||||
G<<
|
||||
GT,
|
||||
GQ.col(0), GQ.col(1), GQ.col(2),
|
||||
GQ.col(0), GQ.col(2), GQ.col(3);
|
||||
J.resize(JT.rows()+2*GQ.rows(),1);
|
||||
J<<JT,DerivedJ::Constant(2*GQ.rows(),1,2*m+1);
|
||||
if(resolve_overlaps)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedJ::Scalar, Eigen::Dynamic,1> SJ;
|
||||
mesh_boolean(
|
||||
DerivedW(W),DerivedG(G),
|
||||
Matrix<typename DerivedVA::Scalar,Dynamic,Dynamic>(),MatrixXI(),
|
||||
MESH_BOOLEAN_TYPE_UNION,
|
||||
W,G,SJ);
|
||||
J.derived() = slice(DerivedJ(J),SJ,1);
|
||||
}
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename sType, int sCols, int sOptions,
|
||||
typename dType, int dCols, int dOptions,
|
||||
typename DerivedW,
|
||||
typename DerivedG,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE void igl::copyleft::cgal::minkowski_sum(
|
||||
const Eigen::MatrixBase<DerivedVA> & VA,
|
||||
const Eigen::MatrixBase<DerivedFA> & FA,
|
||||
const Eigen::Matrix<sType,1,sCols,sOptions> & s,
|
||||
const Eigen::Matrix<dType,1,dCols,dOptions> & d,
|
||||
Eigen::PlainObjectBase<DerivedW> & W,
|
||||
Eigen::PlainObjectBase<DerivedG> & G,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J)
|
||||
{
|
||||
return minkowski_sum(VA,FA,s,d,true,W,G,J);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::minkowski_sum<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, CGAL::Lazy_exact_nt<CGAL::Gmpq>, 3, 1, CGAL::Lazy_exact_nt<CGAL::Gmpq>, 3, 1, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 3, 1, 1, 3> const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 3, 1, 1, 3> const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, 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 void igl::copyleft::cgal::minkowski_sum<
|
||||
Eigen::Matrix<float, -1, 3, 1, -1, 3>,
|
||||
Eigen::Matrix<int, -1, 3, 1, -1, 3>,
|
||||
double, 3, 1,
|
||||
float, 3, 1,
|
||||
Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>,
|
||||
Eigen::Matrix<int, -1, -1, 0, -1, -1>,
|
||||
Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, Eigen::Matrix<float, 1, 3, 1, 1, 3> const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
110
src/igl/copyleft/cgal/minkowski_sum.h
Normal file
110
src/igl/copyleft/cgal/minkowski_sum.h
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
// 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_MINKOWSKI_SUM_H
|
||||
#define IGL_COPYLEFT_CGAL_MINKOWSKI_SUM_H
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Compute the Minkowski sum of a closed triangle mesh (V,F) and a
|
||||
// set of simplices in 3D.
|
||||
//
|
||||
// Inputs:
|
||||
// VA #VA by 3 list of mesh vertices in 3D
|
||||
// FA #FA by 3 list of triangle indices into VA
|
||||
// VB #VB by 3 list of mesh vertices in 3D
|
||||
// FB #FB by ss list of simplex indices into VB, ss<=3
|
||||
// resolve_overlaps whether or not to resolve self-union. If false
|
||||
// then result may contain self-intersections if input mesh is
|
||||
// non-convex.
|
||||
// Outputs:
|
||||
// W #W by 3 list of mesh vertices in 3D
|
||||
// G #G by 3 list of triangle indices into W
|
||||
// J #G by 2 list of indices into
|
||||
//
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedW,
|
||||
typename DerivedG,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE void minkowski_sum(
|
||||
const Eigen::MatrixBase<DerivedVA> & VA,
|
||||
const Eigen::MatrixBase<DerivedFA> & FA,
|
||||
const Eigen::MatrixBase<DerivedVB> & VB,
|
||||
const Eigen::MatrixBase<DerivedFB> & FB,
|
||||
const bool resolve_overlaps,
|
||||
Eigen::PlainObjectBase<DerivedW> & W,
|
||||
Eigen::PlainObjectBase<DerivedG> & G,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J);
|
||||
// Compute the Minkowski sum of a closed triangle mesh (V,F) and a
|
||||
// segment [s,d] in 3D.
|
||||
//
|
||||
// Inputs:
|
||||
// VA #VA by 3 list of mesh vertices in 3D
|
||||
// FA #FA by 3 list of triangle indices into VA
|
||||
// s segment source endpoint in 3D
|
||||
// d segment source endpoint in 3D
|
||||
// resolve_overlaps whether or not to resolve self-union. If false
|
||||
// then result may contain self-intersections if input mesh is
|
||||
// non-convex.
|
||||
// Outputs:
|
||||
// W #W by 3 list of mesh vertices in 3D
|
||||
// G #G by 3 list of triangle indices into W
|
||||
// J #G list of indices into [F;#V+F;[s d]] of birth parents
|
||||
//
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename sType, int sCols, int sOptions,
|
||||
typename dType, int dCols, int dOptions,
|
||||
typename DerivedW,
|
||||
typename DerivedG,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE void minkowski_sum(
|
||||
const Eigen::MatrixBase<DerivedVA> & VA,
|
||||
const Eigen::MatrixBase<DerivedFA> & FA,
|
||||
const Eigen::Matrix<sType,1,sCols,sOptions> & s,
|
||||
const Eigen::Matrix<dType,1,dCols,dOptions> & d,
|
||||
const bool resolve_overlaps,
|
||||
Eigen::PlainObjectBase<DerivedW> & W,
|
||||
Eigen::PlainObjectBase<DerivedG> & G,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J);
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename sType, int sCols, int sOptions,
|
||||
typename dType, int dCols, int dOptions,
|
||||
typename DerivedW,
|
||||
typename DerivedG,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE void minkowski_sum(
|
||||
const Eigen::MatrixBase<DerivedVA> & VA,
|
||||
const Eigen::MatrixBase<DerivedFA> & FA,
|
||||
const Eigen::Matrix<sType,1,sCols,sOptions> & s,
|
||||
const Eigen::Matrix<dType,1,dCols,dOptions> & d,
|
||||
Eigen::PlainObjectBase<DerivedW> & W,
|
||||
Eigen::PlainObjectBase<DerivedG> & G,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "minkowski_sum.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
428
src/igl/copyleft/cgal/order_facets_around_edge.cpp
Normal file
428
src/igl/copyleft/cgal/order_facets_around_edge.cpp
Normal file
|
|
@ -0,0 +1,428 @@
|
|||
#include "order_facets_around_edge.h"
|
||||
#include <Eigen/Geometry>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
// adj_faces contains signed index starting from +- 1.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI >
|
||||
void igl::copyleft::cgal::order_facets_around_edge(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
size_t s,
|
||||
size_t d,
|
||||
const std::vector<int>& adj_faces,
|
||||
Eigen::PlainObjectBase<DerivedI>& order, bool debug)
|
||||
{
|
||||
// Although we only need exact predicates in the algorithm,
|
||||
// exact constructions are needed to avoid degeneracies due to
|
||||
// casting to double.
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel K;
|
||||
typedef K::Point_3 Point_3;
|
||||
typedef K::Plane_3 Plane_3;
|
||||
|
||||
auto get_face_index = [&](int adj_f)->size_t
|
||||
{
|
||||
return abs(adj_f) - 1;
|
||||
};
|
||||
|
||||
auto get_opposite_vertex = [&](size_t fid)->size_t
|
||||
{
|
||||
typedef typename DerivedF::Scalar Index;
|
||||
if (F(fid, 0) != (Index)s && F(fid, 0) != (Index)d) return F(fid, 0);
|
||||
if (F(fid, 1) != (Index)s && F(fid, 1) != (Index)d) return F(fid, 1);
|
||||
if (F(fid, 2) != (Index)s && F(fid, 2) != (Index)d) return F(fid, 2);
|
||||
assert(false);
|
||||
return -1;
|
||||
};
|
||||
|
||||
// Handle base cases
|
||||
if (adj_faces.size() == 0)
|
||||
{
|
||||
order.resize(0, 1);
|
||||
return;
|
||||
} else if (adj_faces.size() == 1)
|
||||
{
|
||||
order.resize(1, 1);
|
||||
order(0, 0) = 0;
|
||||
return;
|
||||
} else if (adj_faces.size() == 2)
|
||||
{
|
||||
const size_t o1 = get_opposite_vertex(get_face_index(adj_faces[0]));
|
||||
const size_t o2 = get_opposite_vertex(get_face_index(adj_faces[1]));
|
||||
const Point_3 ps(V(s, 0), V(s, 1), V(s, 2));
|
||||
const Point_3 pd(V(d, 0), V(d, 1), V(d, 2));
|
||||
const Point_3 p1(V(o1, 0), V(o1, 1), V(o1, 2));
|
||||
const Point_3 p2(V(o2, 0), V(o2, 1), V(o2, 2));
|
||||
order.resize(2, 1);
|
||||
switch (CGAL::orientation(ps, pd, p1, p2))
|
||||
{
|
||||
case CGAL::POSITIVE:
|
||||
order(0, 0) = 1;
|
||||
order(1, 0) = 0;
|
||||
break;
|
||||
case CGAL::NEGATIVE:
|
||||
order(0, 0) = 0;
|
||||
order(1, 0) = 1;
|
||||
break;
|
||||
case CGAL::COPLANAR:
|
||||
{
|
||||
switch (CGAL::coplanar_orientation(ps, pd, p1, p2)) {
|
||||
case CGAL::POSITIVE:
|
||||
// Duplicated face, use index to break tie.
|
||||
order(0, 0) = adj_faces[0] < adj_faces[1] ? 0:1;
|
||||
order(1, 0) = adj_faces[0] < adj_faces[1] ? 1:0;
|
||||
break;
|
||||
case CGAL::NEGATIVE:
|
||||
// Coplanar faces, one on each side of the edge.
|
||||
// It is equally valid to order them (0, 1) or (1, 0).
|
||||
// I cannot think of any reason to prefer one to the
|
||||
// other. So just use (0, 1) ordering by default.
|
||||
order(0, 0) = 0;
|
||||
order(1, 0) = 1;
|
||||
break;
|
||||
case CGAL::COLLINEAR:
|
||||
std::cerr << "Degenerated triangle detected." <<
|
||||
std::endl;
|
||||
assert(false);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t num_adj_faces = adj_faces.size();
|
||||
const size_t o = get_opposite_vertex( get_face_index(adj_faces[0]));
|
||||
const Point_3 p_s(V(s, 0), V(s, 1), V(s, 2));
|
||||
const Point_3 p_d(V(d, 0), V(d, 1), V(d, 2));
|
||||
const Point_3 p_o(V(o, 0), V(o, 1), V(o, 2));
|
||||
const Plane_3 separator(p_s, p_d, p_o);
|
||||
if (separator.is_degenerate()) {
|
||||
throw std::runtime_error(
|
||||
"Cannot order facets around edge due to degenerated facets");
|
||||
}
|
||||
|
||||
std::vector<Point_3> opposite_vertices;
|
||||
for (size_t i=0; i<num_adj_faces; i++)
|
||||
{
|
||||
const size_t o = get_opposite_vertex( get_face_index(adj_faces[i]));
|
||||
opposite_vertices.emplace_back(
|
||||
V(o, 0), V(o, 1), V(o, 2));
|
||||
}
|
||||
|
||||
std::vector<int> positive_side;
|
||||
std::vector<int> negative_side;
|
||||
std::vector<int> tie_positive_oriented;
|
||||
std::vector<int> tie_negative_oriented;
|
||||
|
||||
std::vector<size_t> positive_side_index;
|
||||
std::vector<size_t> negative_side_index;
|
||||
std::vector<size_t> tie_positive_oriented_index;
|
||||
std::vector<size_t> tie_negative_oriented_index;
|
||||
|
||||
for (size_t i=0; i<num_adj_faces; i++)
|
||||
{
|
||||
const int f = adj_faces[i];
|
||||
const Point_3& p_a = opposite_vertices[i];
|
||||
auto orientation = separator.oriented_side(p_a);
|
||||
switch (orientation) {
|
||||
case CGAL::ON_POSITIVE_SIDE:
|
||||
positive_side.push_back(f);
|
||||
positive_side_index.push_back(i);
|
||||
break;
|
||||
case CGAL::ON_NEGATIVE_SIDE:
|
||||
negative_side.push_back(f);
|
||||
negative_side_index.push_back(i);
|
||||
break;
|
||||
case CGAL::ON_ORIENTED_BOUNDARY:
|
||||
{
|
||||
auto inplane_orientation = CGAL::coplanar_orientation(
|
||||
p_s, p_d, p_o, p_a);
|
||||
switch (inplane_orientation) {
|
||||
case CGAL::POSITIVE:
|
||||
tie_positive_oriented.push_back(f);
|
||||
tie_positive_oriented_index.push_back(i);
|
||||
break;
|
||||
case CGAL::NEGATIVE:
|
||||
tie_negative_oriented.push_back(f);
|
||||
tie_negative_oriented_index.push_back(i);
|
||||
break;
|
||||
case CGAL::COLLINEAR:
|
||||
default:
|
||||
throw std::runtime_error(
|
||||
"Degenerated facet detected.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Should not be here.
|
||||
throw std::runtime_error("Unknown CGAL state detected.");
|
||||
}
|
||||
}
|
||||
if (debug) {
|
||||
std::cout << "tie positive: " << std::endl;
|
||||
for (auto& f : tie_positive_oriented) {
|
||||
std::cout << get_face_index(f) << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::cout << "positive side: " << std::endl;
|
||||
for (auto& f : positive_side) {
|
||||
std::cout << get_face_index(f) << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::cout << "tie negative: " << std::endl;
|
||||
for (auto& f : tie_negative_oriented) {
|
||||
std::cout << get_face_index(f) << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::cout << "negative side: " << std::endl;
|
||||
for (auto& f : negative_side) {
|
||||
std::cout << get_face_index(f) << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
auto index_sort = [](std::vector<int>& data) -> std::vector<size_t>{
|
||||
const size_t len = data.size();
|
||||
std::vector<size_t> order(len);
|
||||
for (size_t i=0; i<len; i++) { order[i] = i; }
|
||||
auto comp = [&](size_t i, size_t j) { return data[i] < data[j]; };
|
||||
std::sort(order.begin(), order.end(), comp);
|
||||
return order;
|
||||
};
|
||||
|
||||
DerivedI positive_order, negative_order;
|
||||
order_facets_around_edge(V, F, s, d, positive_side, positive_order, debug);
|
||||
order_facets_around_edge(V, F, s, d, negative_side, negative_order, debug);
|
||||
std::vector<size_t> tie_positive_order = index_sort(tie_positive_oriented);
|
||||
std::vector<size_t> tie_negative_order = index_sort(tie_negative_oriented);
|
||||
|
||||
// Copy results into order vector.
|
||||
const size_t tie_positive_size = tie_positive_oriented.size();
|
||||
const size_t tie_negative_size = tie_negative_oriented.size();
|
||||
const size_t positive_size = positive_order.size();
|
||||
const size_t negative_size = negative_order.size();
|
||||
|
||||
order.resize(
|
||||
tie_positive_size + positive_size + tie_negative_size + negative_size,1);
|
||||
|
||||
size_t count=0;
|
||||
for (size_t i=0; i<tie_positive_size; i++)
|
||||
{
|
||||
order(count+i, 0) = tie_positive_oriented_index[tie_positive_order[i]];
|
||||
}
|
||||
count += tie_positive_size;
|
||||
|
||||
for (size_t i=0; i<negative_size; i++)
|
||||
{
|
||||
order(count+i, 0) = negative_side_index[negative_order(i, 0)];
|
||||
}
|
||||
count += negative_size;
|
||||
|
||||
for (size_t i=0; i<tie_negative_size; i++)
|
||||
{
|
||||
order(count+i, 0) = tie_negative_oriented_index[tie_negative_order[i]];
|
||||
}
|
||||
count += tie_negative_size;
|
||||
|
||||
for (size_t i=0; i<positive_size; i++)
|
||||
{
|
||||
order(count+i, 0) = positive_side_index[positive_order(i, 0)];
|
||||
}
|
||||
count += positive_size;
|
||||
assert(count == num_adj_faces);
|
||||
|
||||
// Find the correct start point.
|
||||
size_t start_idx = 0;
|
||||
for (size_t i=0; i<num_adj_faces; i++)
|
||||
{
|
||||
const Point_3& p_a = opposite_vertices[order(i, 0)];
|
||||
const Point_3& p_b =
|
||||
opposite_vertices[order((i+1)%num_adj_faces, 0)];
|
||||
auto orientation = CGAL::orientation(p_s, p_d, p_a, p_b);
|
||||
if (orientation == CGAL::POSITIVE)
|
||||
{
|
||||
// Angle between triangle (p_s, p_d, p_a) and (p_s, p_d, p_b) is
|
||||
// more than 180 degrees.
|
||||
start_idx = (i+1)%num_adj_faces;
|
||||
break;
|
||||
} else if (orientation == CGAL::COPLANAR &&
|
||||
Plane_3(p_s, p_d, p_a).orthogonal_direction() !=
|
||||
Plane_3(p_s, p_d, p_b).orthogonal_direction())
|
||||
{
|
||||
// All 4 points are coplanar, but p_a and p_b are on each side of
|
||||
// the edge (p_s, p_d). This means the angle between triangle
|
||||
// (p_s, p_d, p_a) and (p_s, p_d, p_b) is exactly 180 degrees.
|
||||
start_idx = (i+1)%num_adj_faces;
|
||||
break;
|
||||
}
|
||||
}
|
||||
DerivedI circular_order = order;
|
||||
for (size_t i=0; i<num_adj_faces; i++)
|
||||
{
|
||||
order(i, 0) = circular_order((start_idx + i)%num_adj_faces, 0);
|
||||
}
|
||||
}
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI>
|
||||
IGL_INLINE
|
||||
void igl::copyleft::cgal::order_facets_around_edge(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
size_t s,
|
||||
size_t d,
|
||||
const std::vector<int>& adj_faces,
|
||||
const Eigen::PlainObjectBase<DerivedV>& pivot_point,
|
||||
Eigen::PlainObjectBase<DerivedI>& order)
|
||||
{
|
||||
assert(V.cols() == 3);
|
||||
assert(F.cols() == 3);
|
||||
assert(pivot_point.cols() == 3);
|
||||
auto signed_index_to_index = [&](int signed_idx)
|
||||
{
|
||||
return abs(signed_idx) -1;
|
||||
};
|
||||
auto get_opposite_vertex_index = [&](size_t fid) -> typename DerivedF::Scalar
|
||||
{
|
||||
typedef typename DerivedF::Scalar Index;
|
||||
if (F(fid, 0) != (Index)s && F(fid, 0) != (Index)d) return F(fid, 0);
|
||||
if (F(fid, 1) != (Index)s && F(fid, 1) != (Index)d) return F(fid, 1);
|
||||
if (F(fid, 2) != (Index)s && F(fid, 2) != (Index)d) return F(fid, 2);
|
||||
assert(false);
|
||||
// avoid warning
|
||||
return -1;
|
||||
};
|
||||
|
||||
{
|
||||
// Check if s, d and pivot are collinear.
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel K;
|
||||
K::Point_3 ps(V(s,0), V(s,1), V(s,2));
|
||||
K::Point_3 pd(V(d,0), V(d,1), V(d,2));
|
||||
K::Point_3 pp(pivot_point(0,0), pivot_point(0,1), pivot_point(0,2));
|
||||
if (CGAL::collinear(ps, pd, pp)) {
|
||||
throw std::runtime_error(
|
||||
"Pivot point is collinear with the outer edge!");
|
||||
}
|
||||
}
|
||||
|
||||
const size_t N = adj_faces.size();
|
||||
const size_t num_faces = N + 1; // N adj faces + 1 pivot face
|
||||
|
||||
// Because face indices are used for tie breaking, the original face indices
|
||||
// in the new faces array must be ascending.
|
||||
auto comp = [&](int i, int j)
|
||||
{
|
||||
return signed_index_to_index(adj_faces[i]) <
|
||||
signed_index_to_index(adj_faces[j]);
|
||||
};
|
||||
std::vector<size_t> adj_order(N);
|
||||
for (size_t i=0; i<N; i++) adj_order[i] = i;
|
||||
std::sort(adj_order.begin(), adj_order.end(), comp);
|
||||
|
||||
DerivedV vertices(num_faces + 2, 3);
|
||||
for (size_t i=0; i<N; i++)
|
||||
{
|
||||
const size_t fid = signed_index_to_index(adj_faces[adj_order[i]]);
|
||||
vertices.row(i) = V.row(get_opposite_vertex_index(fid));
|
||||
}
|
||||
vertices.row(N ) = pivot_point;
|
||||
vertices.row(N+1) = V.row(s);
|
||||
vertices.row(N+2) = V.row(d);
|
||||
|
||||
DerivedF faces(num_faces, 3);
|
||||
for (size_t i=0; i<N; i++)
|
||||
{
|
||||
if (adj_faces[adj_order[i]] < 0)
|
||||
{
|
||||
faces(i,0) = N+1; // s
|
||||
faces(i,1) = N+2; // d
|
||||
faces(i,2) = i ;
|
||||
} else
|
||||
{
|
||||
faces(i,0) = N+2; // d
|
||||
faces(i,1) = N+1; // s
|
||||
faces(i,2) = i ;
|
||||
}
|
||||
}
|
||||
// Last face is the pivot face.
|
||||
faces(N, 0) = N+1;
|
||||
faces(N, 1) = N+2;
|
||||
faces(N, 2) = N;
|
||||
|
||||
std::vector<int> adj_faces_with_pivot(num_faces);
|
||||
for (size_t i=0; i<num_faces; i++)
|
||||
{
|
||||
if ((size_t)faces(i,0) == N+1 && (size_t)faces(i,1) == N+2)
|
||||
{
|
||||
adj_faces_with_pivot[i] = int(i+1) * -1;
|
||||
} else
|
||||
{
|
||||
adj_faces_with_pivot[i] = int(i+1);
|
||||
}
|
||||
}
|
||||
|
||||
DerivedI order_with_pivot;
|
||||
order_facets_around_edge(
|
||||
vertices, faces, N+1, N+2, adj_faces_with_pivot, order_with_pivot);
|
||||
|
||||
assert((size_t)order_with_pivot.size() == num_faces);
|
||||
order.resize(N);
|
||||
size_t pivot_index = num_faces + 1;
|
||||
for (size_t i=0; i<num_faces; i++)
|
||||
{
|
||||
if ((size_t)order_with_pivot[i] == N)
|
||||
{
|
||||
pivot_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(pivot_index < num_faces);
|
||||
|
||||
for (size_t i=0; i<N; i++)
|
||||
{
|
||||
order[i] = adj_order[order_with_pivot[(pivot_index+i+1)%num_faces]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, bool);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, bool);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, bool);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, bool);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<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&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#ifdef WIN32
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &, bool);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &, bool);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &, bool);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 0, -1, 3>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<double, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<double, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 0, -1, 3>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
|
||||
#endif
|
||||
#endif
|
||||
77
src/igl/copyleft/cgal/order_facets_around_edge.h
Normal file
77
src/igl/copyleft/cgal/order_facets_around_edge.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
// 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_ORDER_FACETS_AROUND_EDGE_H
|
||||
#define IGL_COPYLEFT_CGAL_ORDER_FACETS_AROUND_EDGE_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Given a directed edge, sort its adjacent faces. Assuming the
|
||||
// directed edge is (s, d). Sort the adjacent faces clockwise around the
|
||||
// axis (d - s), i.e. left-hand rule. An adjacent face is consistently
|
||||
// oriented if it contains (d, s) as a directed edge.
|
||||
//
|
||||
// For overlapping faces, break the tie using signed face index, smaller
|
||||
// signed index comes before the larger signed index. Signed index is
|
||||
// computed as (consistent? 1:-1) * (face_index + 1).
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertices.
|
||||
// F #F by 3 list of faces
|
||||
// s Index of source vertex.
|
||||
// d Index of destination vertex.
|
||||
// adj_faces List of adjacent face signed indices.
|
||||
// Output:
|
||||
// order List of face indices that orders adjacent faces around edge
|
||||
// (s, d) clockwise.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI >
|
||||
IGL_INLINE
|
||||
void order_facets_around_edge(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
size_t s,
|
||||
size_t d,
|
||||
const std::vector<int>& adj_faces,
|
||||
Eigen::PlainObjectBase<DerivedI>& order,
|
||||
bool debug=false);
|
||||
|
||||
// This function is a wrapper around the one above. Since the ordering
|
||||
// is circular, the pivot point is used to define a starting point. So
|
||||
// order[0] is the index into adj_face that is immediately after the
|
||||
// pivot face (s, d, pivot point) in clockwise order.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI>
|
||||
IGL_INLINE
|
||||
void order_facets_around_edge(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
size_t s,
|
||||
size_t d,
|
||||
const std::vector<int>& adj_faces,
|
||||
const Eigen::PlainObjectBase<DerivedV>& pivot_point,
|
||||
Eigen::PlainObjectBase<DerivedI>& order);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
#include "order_facets_around_edge.cpp"
|
||||
#endif
|
||||
#endif
|
||||
332
src/igl/copyleft/cgal/order_facets_around_edges.cpp
Normal file
332
src/igl/copyleft/cgal/order_facets_around_edges.cpp
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
// 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 "order_facets_around_edges.h"
|
||||
#include "order_facets_around_edge.h"
|
||||
#include "../../sort_angles.h"
|
||||
#include <Eigen/Geometry>
|
||||
#include <type_traits>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedN,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename uE2oEType,
|
||||
typename uE2CType >
|
||||
IGL_INLINE
|
||||
typename std::enable_if<!std::is_same<typename DerivedV::Scalar,
|
||||
typename CGAL::Exact_predicates_exact_constructions_kernel::FT>::value, void>::type
|
||||
igl::copyleft::cgal::order_facets_around_edges(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedN>& N,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
std::vector<std::vector<uE2oEType> >& uE2oE,
|
||||
std::vector<std::vector<uE2CType > >& uE2C ) {
|
||||
|
||||
typedef Eigen::Matrix<typename DerivedN::Scalar, 3, 1> Vector3F;
|
||||
const typename DerivedV::Scalar EPS = 1e-12;
|
||||
const size_t num_faces = F.rows();
|
||||
const size_t num_undirected_edges = uE.rows();
|
||||
|
||||
auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; };
|
||||
auto edge_index_to_corner_index = [&](size_t ei) { return ei / num_faces; };
|
||||
|
||||
uE2oE.resize(num_undirected_edges);
|
||||
uE2C.resize(num_undirected_edges);
|
||||
|
||||
for(size_t ui = 0;ui<num_undirected_edges;ui++)
|
||||
{
|
||||
const auto& adj_edges = uE2E[ui];
|
||||
const size_t edge_valance = adj_edges.size();
|
||||
assert(edge_valance > 0);
|
||||
|
||||
const auto ref_edge = adj_edges[0];
|
||||
const auto ref_face = edge_index_to_face_index(ref_edge);
|
||||
Vector3F ref_normal = N.row(ref_face);
|
||||
|
||||
const auto ref_corner_o = edge_index_to_corner_index(ref_edge);
|
||||
const auto ref_corner_s = (ref_corner_o+1)%3;
|
||||
const auto ref_corner_d = (ref_corner_o+2)%3;
|
||||
|
||||
const typename DerivedF::Scalar o = F(ref_face, ref_corner_o);
|
||||
const typename DerivedF::Scalar s = F(ref_face, ref_corner_s);
|
||||
const typename DerivedF::Scalar d = F(ref_face, ref_corner_d);
|
||||
|
||||
Vector3F edge = V.row(d) - V.row(s);
|
||||
auto edge_len = edge.norm();
|
||||
bool degenerated = edge_len < EPS;
|
||||
if (degenerated) {
|
||||
if (edge_valance <= 2) {
|
||||
// There is only one way to order 2 or less faces.
|
||||
edge.setZero();
|
||||
} else {
|
||||
edge.setZero();
|
||||
Eigen::Matrix<typename DerivedN::Scalar, Eigen::Dynamic, 3>
|
||||
normals(edge_valance, 3);
|
||||
for (size_t fei=0; fei<edge_valance; fei++) {
|
||||
const auto fe = adj_edges[fei];
|
||||
const auto f = edge_index_to_face_index(fe);
|
||||
normals.row(fei) = N.row(f);
|
||||
}
|
||||
for (size_t i=0; i<edge_valance; i++) {
|
||||
size_t j = (i+1) % edge_valance;
|
||||
Vector3F ni = normals.row(i);
|
||||
Vector3F nj = normals.row(j);
|
||||
edge = ni.cross(nj);
|
||||
edge_len = edge.norm();
|
||||
if (edge_len >= EPS) {
|
||||
edge.normalize();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure edge direction are consistent with reference face.
|
||||
Vector3F in_face_vec = V.row(o) - V.row(s);
|
||||
if (edge.cross(in_face_vec).dot(ref_normal) < 0) {
|
||||
edge *= -1;
|
||||
}
|
||||
|
||||
if (edge.norm() < EPS) {
|
||||
std::cerr << "=====================================" << std::endl;
|
||||
std::cerr << " ui: " << ui << std::endl;
|
||||
std::cerr << "edge: " << ref_edge << std::endl;
|
||||
std::cerr << "face: " << ref_face << std::endl;
|
||||
std::cerr << " vs: " << V.row(s) << std::endl;
|
||||
std::cerr << " vd: " << V.row(d) << std::endl;
|
||||
std::cerr << "adj face normals: " << std::endl;
|
||||
std::cerr << normals << std::endl;
|
||||
std::cerr << "Very degenerated case detected:" << std::endl;
|
||||
std::cerr << "Near zero edge surrounded by "
|
||||
<< edge_valance << " neearly colinear faces" <<
|
||||
std::endl;
|
||||
std::cerr << "=====================================" << std::endl;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
edge.normalize();
|
||||
}
|
||||
|
||||
Eigen::MatrixXd angle_data(edge_valance, 3);
|
||||
std::vector<bool> cons(edge_valance);
|
||||
|
||||
for (size_t fei=0; fei<edge_valance; fei++) {
|
||||
const auto fe = adj_edges[fei];
|
||||
const auto f = edge_index_to_face_index(fe);
|
||||
const auto c = edge_index_to_corner_index(fe);
|
||||
cons[fei] = (d == F(f, (c+1)%3));
|
||||
assert( cons[fei] || (d == F(f,(c+2)%3)));
|
||||
assert(!cons[fei] || (s == F(f,(c+2)%3)));
|
||||
assert(!cons[fei] || (d == F(f,(c+1)%3)));
|
||||
Vector3F n = N.row(f);
|
||||
angle_data(fei, 0) = ref_normal.cross(n).dot(edge);
|
||||
angle_data(fei, 1) = ref_normal.dot(n);
|
||||
if (cons[fei]) {
|
||||
angle_data(fei, 0) *= -1;
|
||||
angle_data(fei, 1) *= -1;
|
||||
}
|
||||
angle_data(fei, 0) *= -1; // Sort clockwise.
|
||||
angle_data(fei, 2) = (cons[fei]?1.:-1.)*(f+1);
|
||||
}
|
||||
|
||||
Eigen::VectorXi order;
|
||||
igl::sort_angles(angle_data, order);
|
||||
|
||||
auto& ordered_edges = uE2oE[ui];
|
||||
auto& consistency = uE2C[ui];
|
||||
|
||||
ordered_edges.resize(edge_valance);
|
||||
consistency.resize(edge_valance);
|
||||
for (size_t fei=0; fei<edge_valance; fei++) {
|
||||
ordered_edges[fei] = adj_edges[order[fei]];
|
||||
consistency[fei] = cons[order[fei]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedN,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename uE2oEType,
|
||||
typename uE2CType >
|
||||
IGL_INLINE
|
||||
typename std::enable_if<std::is_same<typename DerivedV::Scalar,
|
||||
typename CGAL::Exact_predicates_exact_constructions_kernel::FT>::value, void>::type
|
||||
igl::copyleft::cgal::order_facets_around_edges(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedN>& N,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
std::vector<std::vector<uE2oEType> >& uE2oE,
|
||||
std::vector<std::vector<uE2CType > >& uE2C ) {
|
||||
|
||||
typedef Eigen::Matrix<typename DerivedN::Scalar, 3, 1> Vector3F;
|
||||
typedef Eigen::Matrix<typename DerivedV::Scalar, 3, 1> Vector3E;
|
||||
const typename DerivedV::Scalar EPS = 1e-12;
|
||||
const size_t num_faces = F.rows();
|
||||
const size_t num_undirected_edges = uE.rows();
|
||||
|
||||
auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; };
|
||||
auto edge_index_to_corner_index = [&](size_t ei) { return ei / num_faces; };
|
||||
|
||||
uE2oE.resize(num_undirected_edges);
|
||||
uE2C.resize(num_undirected_edges);
|
||||
|
||||
for(size_t ui = 0;ui<num_undirected_edges;ui++)
|
||||
{
|
||||
const auto& adj_edges = uE2E[ui];
|
||||
const size_t edge_valance = adj_edges.size();
|
||||
assert(edge_valance > 0);
|
||||
|
||||
const auto ref_edge = adj_edges[0];
|
||||
const auto ref_face = edge_index_to_face_index(ref_edge);
|
||||
Vector3F ref_normal = N.row(ref_face);
|
||||
|
||||
const auto ref_corner_o = edge_index_to_corner_index(ref_edge);
|
||||
const auto ref_corner_s = (ref_corner_o+1)%3;
|
||||
const auto ref_corner_d = (ref_corner_o+2)%3;
|
||||
|
||||
const typename DerivedF::Scalar o = F(ref_face, ref_corner_o);
|
||||
const typename DerivedF::Scalar s = F(ref_face, ref_corner_s);
|
||||
const typename DerivedF::Scalar d = F(ref_face, ref_corner_d);
|
||||
|
||||
Vector3E exact_edge = V.row(d) - V.row(s);
|
||||
exact_edge.array() /= exact_edge.squaredNorm();
|
||||
Vector3F edge(
|
||||
CGAL::to_double(exact_edge[0]),
|
||||
CGAL::to_double(exact_edge[1]),
|
||||
CGAL::to_double(exact_edge[2]));
|
||||
edge.normalize();
|
||||
|
||||
Eigen::MatrixXd angle_data(edge_valance, 3);
|
||||
std::vector<bool> cons(edge_valance);
|
||||
|
||||
for (size_t fei=0; fei<edge_valance; fei++) {
|
||||
const auto fe = adj_edges[fei];
|
||||
const auto f = edge_index_to_face_index(fe);
|
||||
const auto c = edge_index_to_corner_index(fe);
|
||||
cons[fei] = (d == F(f, (c+1)%3));
|
||||
assert( cons[fei] || (d == F(f,(c+2)%3)));
|
||||
assert(!cons[fei] || (s == F(f,(c+2)%3)));
|
||||
assert(!cons[fei] || (d == F(f,(c+1)%3)));
|
||||
Vector3F n = N.row(f);
|
||||
angle_data(fei, 0) = ref_normal.cross(n).dot(edge);
|
||||
angle_data(fei, 1) = ref_normal.dot(n);
|
||||
if (cons[fei]) {
|
||||
angle_data(fei, 0) *= -1;
|
||||
angle_data(fei, 1) *= -1;
|
||||
}
|
||||
angle_data(fei, 0) *= -1; // Sort clockwise.
|
||||
angle_data(fei, 2) = (cons[fei]?1.:-1.)*(f+1);
|
||||
}
|
||||
|
||||
Eigen::VectorXi order;
|
||||
igl::sort_angles(angle_data, order);
|
||||
|
||||
auto& ordered_edges = uE2oE[ui];
|
||||
auto& consistency = uE2C[ui];
|
||||
|
||||
ordered_edges.resize(edge_valance);
|
||||
consistency.resize(edge_valance);
|
||||
for (size_t fei=0; fei<edge_valance; fei++) {
|
||||
ordered_edges[fei] = adj_edges[order[fei]];
|
||||
consistency[fei] = cons[order[fei]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename uE2oEType,
|
||||
typename uE2CType >
|
||||
IGL_INLINE void igl::copyleft::cgal::order_facets_around_edges(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
std::vector<std::vector<uE2oEType> >& uE2oE,
|
||||
std::vector<std::vector<uE2CType > >& uE2C ) {
|
||||
|
||||
//typedef Eigen::Matrix<typename DerivedV::Scalar, 3, 1> Vector3E;
|
||||
const size_t num_faces = F.rows();
|
||||
const size_t num_undirected_edges = uE.rows();
|
||||
|
||||
auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; };
|
||||
auto edge_index_to_corner_index = [&](size_t ei) { return ei / num_faces; };
|
||||
|
||||
uE2oE.resize(num_undirected_edges);
|
||||
uE2C.resize(num_undirected_edges);
|
||||
|
||||
for(size_t ui = 0;ui<num_undirected_edges;ui++)
|
||||
{
|
||||
const auto& adj_edges = uE2E[ui];
|
||||
const size_t edge_valance = adj_edges.size();
|
||||
assert(edge_valance > 0);
|
||||
|
||||
const auto ref_edge = adj_edges[0];
|
||||
const auto ref_face = edge_index_to_face_index(ref_edge);
|
||||
|
||||
const auto ref_corner_o = edge_index_to_corner_index(ref_edge);
|
||||
const auto ref_corner_s = (ref_corner_o+1)%3;
|
||||
const auto ref_corner_d = (ref_corner_o+2)%3;
|
||||
|
||||
//const typename DerivedF::Scalar o = F(ref_face, ref_corner_o);
|
||||
const typename DerivedF::Scalar s = F(ref_face, ref_corner_s);
|
||||
const typename DerivedF::Scalar d = F(ref_face, ref_corner_d);
|
||||
|
||||
std::vector<bool> cons(edge_valance);
|
||||
std::vector<int> adj_faces(edge_valance);
|
||||
for (size_t fei=0; fei<edge_valance; fei++) {
|
||||
const auto fe = adj_edges[fei];
|
||||
const auto f = edge_index_to_face_index(fe);
|
||||
const auto c = edge_index_to_corner_index(fe);
|
||||
cons[fei] = (d == F(f, (c+1)%3));
|
||||
adj_faces[fei] = (f+1) * (cons[fei] ? 1:-1);
|
||||
|
||||
assert( cons[fei] || (d == F(f,(c+2)%3)));
|
||||
assert(!cons[fei] || (s == F(f,(c+2)%3)));
|
||||
assert(!cons[fei] || (d == F(f,(c+1)%3)));
|
||||
}
|
||||
|
||||
Eigen::VectorXi order;
|
||||
order_facets_around_edge(V, F, s, d, adj_faces, order);
|
||||
assert((size_t)order.size() == edge_valance);
|
||||
|
||||
auto& ordered_edges = uE2oE[ui];
|
||||
auto& consistency = uE2C[ui];
|
||||
|
||||
ordered_edges.resize(edge_valance);
|
||||
consistency.resize(edge_valance);
|
||||
for (size_t fei=0; fei<edge_valance; fei++) {
|
||||
ordered_edges[fei] = adj_edges[order[fei]];
|
||||
consistency[fei] = cons[order[fei]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::order_facets_around_edges<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int, int, bool>(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&, 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> > > >&, std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > >&);
|
||||
// generated by autoexplicit.sh
|
||||
template std::enable_if<!(std::is_same<Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, CGAL::Lazy_exact_nt<CGAL::Gmpq> >::value), void>::type igl::copyleft::cgal::order_facets_around_edges<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>, int, int, bool>(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&, 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> > > >&, std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > >&);
|
||||
template void igl::copyleft::cgal::order_facets_around_edges<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, long, long, bool>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&, std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > >&);
|
||||
template void igl::copyleft::cgal::order_facets_around_edges<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, long, long, bool>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&, std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > >&);
|
||||
template void igl::copyleft::cgal::order_facets_around_edges<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, long, long, bool>(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, 2, 0, -1, 2> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&, std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > >&);
|
||||
template void igl::copyleft::cgal::order_facets_around_edges<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, long, long, bool>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&, std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > >&);
|
||||
#endif
|
||||
107
src/igl/copyleft/cgal/order_facets_around_edges.h
Normal file
107
src/igl/copyleft/cgal/order_facets_around_edges.h
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
// 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_ORDER_FACETS_AROUND_EDGES_H
|
||||
#define IGL_COPYLEFT_CGAL_ORDER_FACETS_AROUND_EDGES_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <vector>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// For each undirected edge, sort its adjacent faces. Assuming the
|
||||
// undirected edge is (s, d). Sort the adjacent faces clockwise around the
|
||||
// axis (d - s), i.e. left-hand rule. An adjacent face is consistently
|
||||
// oriented if it contains (d, s) as a directed edge.
|
||||
//
|
||||
// For overlapping faces, break the tie using signed face index, smaller
|
||||
// signed index comes before the larger signed index. Signed index is
|
||||
// computed as (consistent? 1:-1) * index.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertices.
|
||||
// F #F by 3 list of faces
|
||||
// N #F by 3 list of face normals.
|
||||
// uE #uE by 2 list of vertex_indices, represents undirected edges.
|
||||
// uE2E #uE list of lists that maps uE to E. (a one-to-many map)
|
||||
//
|
||||
// Outputs:
|
||||
// uE2oE #uE list of lists that maps uE to an ordered list of E. (a
|
||||
// one-to-many map)
|
||||
// uE2C #uE list of lists of bools indicates whether each face in
|
||||
// uE2oE[i] is consistently orientated as the ordering.
|
||||
//
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedN,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename uE2oEType,
|
||||
typename uE2CType >
|
||||
IGL_INLINE
|
||||
typename std::enable_if<!std::is_same<typename DerivedV::Scalar,
|
||||
typename CGAL::Exact_predicates_exact_constructions_kernel::FT>::value, void>::type
|
||||
order_facets_around_edges(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedN>& N,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
std::vector<std::vector<uE2oEType> >& uE2oE,
|
||||
std::vector<std::vector<uE2CType > >& uE2C );
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedN,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename uE2oEType,
|
||||
typename uE2CType >
|
||||
IGL_INLINE
|
||||
typename std::enable_if<std::is_same<typename DerivedV::Scalar,
|
||||
typename CGAL::Exact_predicates_exact_constructions_kernel::FT>::value, void>::type
|
||||
order_facets_around_edges(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedN>& N,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
std::vector<std::vector<uE2oEType> >& uE2oE,
|
||||
std::vector<std::vector<uE2CType > >& uE2C );
|
||||
|
||||
// Order faces around each edge. Only exact predicate is used in the algorithm.
|
||||
// Normal is not needed.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename uE2oEType,
|
||||
typename uE2CType >
|
||||
IGL_INLINE void order_facets_around_edges(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
std::vector<std::vector<uE2oEType> >& uE2oE,
|
||||
std::vector<std::vector<uE2CType > >& uE2C );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
#include "order_facets_around_edges.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
37
src/igl/copyleft/cgal/orient2D.cpp
Normal file
37
src/igl/copyleft/cgal/orient2D.cpp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// 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 "orient2D.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::orient2D(
|
||||
const Scalar pa[2],
|
||||
const Scalar pb[2],
|
||||
const Scalar pc[2])
|
||||
{
|
||||
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::orientation(
|
||||
typename Kernel::Point_2(pa[0], pa[1]),
|
||||
typename Kernel::Point_2(pb[0], pb[1]),
|
||||
typename Kernel::Point_2(pc[0], pc[1]))) {
|
||||
case CGAL::LEFT_TURN:
|
||||
return 1;
|
||||
case CGAL::RIGHT_TURN:
|
||||
return -1;
|
||||
case CGAL::COLLINEAR:
|
||||
return 0;
|
||||
default:
|
||||
throw "Invalid orientation";
|
||||
}
|
||||
}
|
||||
38
src/igl/copyleft/cgal/orient2D.h
Normal file
38
src/igl/copyleft/cgal/orient2D.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
// 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_ORIENT_2D_H
|
||||
#define IGL_COPYLEFT_CGAL_ORIENT_2D_H
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Inputs:
|
||||
// pa,pb,pc 2D points.
|
||||
// Output:
|
||||
// 1 if pa,pb,pc are counterclockwise oriented.
|
||||
// 0 if pa,pb,pc are counterclockwise oriented.
|
||||
// -1 if pa,pb,pc are clockwise oriented.
|
||||
template <typename Scalar>
|
||||
IGL_INLINE short orient2D(
|
||||
const Scalar pa[2],
|
||||
const Scalar pb[2],
|
||||
const Scalar pc[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "orient2D.cpp"
|
||||
#endif
|
||||
#endif
|
||||
39
src/igl/copyleft/cgal/orient3D.cpp
Normal file
39
src/igl/copyleft/cgal/orient3D.cpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// 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 "orient3D.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::orient3D(
|
||||
const Scalar pa[3],
|
||||
const Scalar pb[3],
|
||||
const Scalar pc[3],
|
||||
const Scalar pd[3])
|
||||
{
|
||||
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::orientation(
|
||||
typename Kernel::Point_3(pa[0], pa[1], pa[2]),
|
||||
typename Kernel::Point_3(pb[0], pb[1], pb[2]),
|
||||
typename Kernel::Point_3(pc[0], pc[1], pc[2]),
|
||||
typename Kernel::Point_3(pd[0], pd[1], pd[2]))) {
|
||||
case CGAL::POSITIVE:
|
||||
return 1;
|
||||
case CGAL::NEGATIVE:
|
||||
return -1;
|
||||
case CGAL::COPLANAR:
|
||||
return 0;
|
||||
default:
|
||||
throw "Invalid orientation";
|
||||
}
|
||||
}
|
||||
39
src/igl/copyleft/cgal/orient3D.h
Normal file
39
src/igl/copyleft/cgal/orient3D.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// 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_ORIENT_3D_H
|
||||
#define IGL_COPYLEFT_CGAL_ORIENT_3D_H
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Inputs:
|
||||
// pa,pb,pc,pd 3D points.
|
||||
// Output:
|
||||
// 1 if pa,pb,pc,pd forms a tet of positive volume.
|
||||
// 0 if pa,pb,pc,pd are coplanar.
|
||||
// -1 if pa,pb,pc,pd forms a tet of negative volume.
|
||||
template <typename Scalar>
|
||||
IGL_INLINE short orient3D(
|
||||
const Scalar pa[3],
|
||||
const Scalar pb[3],
|
||||
const Scalar pc[3],
|
||||
const Scalar pd[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "orient3D.cpp"
|
||||
#endif
|
||||
#endif
|
||||
232
src/igl/copyleft/cgal/outer_element.cpp
Normal file
232
src/igl/copyleft/cgal/outer_element.cpp
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
// 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 "outer_element.h"
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename IndexType,
|
||||
typename DerivedA
|
||||
>
|
||||
IGL_INLINE void igl::copyleft::cgal::outer_vertex(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
const Eigen::PlainObjectBase<DerivedI> & I,
|
||||
IndexType & v_index,
|
||||
Eigen::PlainObjectBase<DerivedA> & A)
|
||||
{
|
||||
// Algorithm:
|
||||
// Find an outer vertex (i.e. vertex reachable from infinity)
|
||||
// Return the vertex with the largest X value.
|
||||
// If there is a tie, pick the one with largest Y value.
|
||||
// If there is still a tie, pick the one with the largest Z value.
|
||||
// If there is still a tie, then there are duplicated vertices within the
|
||||
// mesh, which violates the precondition.
|
||||
typedef typename DerivedF::Scalar Index;
|
||||
const Index INVALID = std::numeric_limits<Index>::max();
|
||||
const size_t num_selected_faces = I.rows();
|
||||
std::vector<size_t> candidate_faces;
|
||||
Index outer_vid = INVALID;
|
||||
typename DerivedV::Scalar outer_val = 0;
|
||||
for (size_t i=0; i<num_selected_faces; i++)
|
||||
{
|
||||
size_t f = I(i);
|
||||
for (size_t j=0; j<3; j++)
|
||||
{
|
||||
Index v = F(f, j);
|
||||
auto vx = V(v, 0);
|
||||
if (outer_vid == INVALID || vx > outer_val)
|
||||
{
|
||||
outer_val = vx;
|
||||
outer_vid = v;
|
||||
candidate_faces = {f};
|
||||
} else if (v == outer_vid)
|
||||
{
|
||||
candidate_faces.push_back(f);
|
||||
} else if (vx == outer_val)
|
||||
{
|
||||
// Break tie.
|
||||
auto vy = V(v,1);
|
||||
auto vz = V(v, 2);
|
||||
auto outer_y = V(outer_vid, 1);
|
||||
auto outer_z = V(outer_vid, 2);
|
||||
assert(!(vy == outer_y && vz == outer_z));
|
||||
bool replace = (vy > outer_y) ||
|
||||
((vy == outer_y) && (vz > outer_z));
|
||||
if (replace)
|
||||
{
|
||||
outer_val = vx;
|
||||
outer_vid = v;
|
||||
candidate_faces = {f};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(outer_vid != INVALID);
|
||||
assert(candidate_faces.size() > 0);
|
||||
v_index = outer_vid;
|
||||
A.resize(candidate_faces.size());
|
||||
std::copy(candidate_faces.begin(), candidate_faces.end(), A.data());
|
||||
}
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename IndexType,
|
||||
typename DerivedA
|
||||
>
|
||||
IGL_INLINE void igl::copyleft::cgal::outer_edge(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
const Eigen::PlainObjectBase<DerivedI> & I,
|
||||
IndexType & v1,
|
||||
IndexType & v2,
|
||||
Eigen::PlainObjectBase<DerivedA> & A) {
|
||||
// Algorithm:
|
||||
// Find an outer vertex first.
|
||||
// Find the incident edge with largest abs slope when projected onto XY plane.
|
||||
// If there is a tie, check the signed slope and use the positive one.
|
||||
// If there is still a tie, break it using the projected slope onto ZX plane.
|
||||
// If there is still a tie, again check the signed slope and use the positive one.
|
||||
// If there is still a tie, then there are multiple overlapping edges,
|
||||
// which violates the precondition.
|
||||
typedef typename DerivedV::Scalar Scalar;
|
||||
typedef typename DerivedV::Index Index;
|
||||
typedef typename Eigen::Matrix<Scalar, 3, 1> ScalarArray3;
|
||||
typedef typename Eigen::Matrix<typename DerivedF::Scalar, 3, 1> IndexArray3;
|
||||
const Index INVALID = std::numeric_limits<Index>::max();
|
||||
|
||||
Index outer_vid;
|
||||
Eigen::Matrix<Index,Eigen::Dynamic,1> candidate_faces;
|
||||
outer_vertex(V, F, I, outer_vid, candidate_faces);
|
||||
const ScalarArray3& outer_v = V.row(outer_vid);
|
||||
assert(candidate_faces.size() > 0);
|
||||
|
||||
auto get_vertex_index = [&](const IndexArray3& f, Index vid) -> Index
|
||||
{
|
||||
if (f[0] == vid) return 0;
|
||||
if (f[1] == vid) return 1;
|
||||
if (f[2] == vid) return 2;
|
||||
assert(false);
|
||||
return -1;
|
||||
};
|
||||
|
||||
auto unsigned_value = [](Scalar v) -> Scalar {
|
||||
if (v < 0) return v * -1;
|
||||
else return v;
|
||||
};
|
||||
|
||||
Scalar outer_slope_YX = 0;
|
||||
Scalar outer_slope_ZX = 0;
|
||||
Index outer_opp_vid = INVALID;
|
||||
bool infinite_slope_detected = false;
|
||||
std::vector<Index> incident_faces;
|
||||
auto check_and_update_outer_edge = [&](Index opp_vid, Index fid) -> void {
|
||||
if (opp_vid == outer_opp_vid)
|
||||
{
|
||||
incident_faces.push_back(fid);
|
||||
return;
|
||||
}
|
||||
|
||||
const ScalarArray3 opp_v = V.row(opp_vid);
|
||||
if (!infinite_slope_detected && outer_v[0] != opp_v[0])
|
||||
{
|
||||
// Finite slope
|
||||
const ScalarArray3 diff = opp_v - outer_v;
|
||||
const Scalar slope_YX = diff[1] / diff[0];
|
||||
const Scalar slope_ZX = diff[2] / diff[0];
|
||||
const Scalar u_slope_YX = unsigned_value(slope_YX);
|
||||
const Scalar u_slope_ZX = unsigned_value(slope_ZX);
|
||||
bool update = false;
|
||||
if (outer_opp_vid == INVALID) {
|
||||
update = true;
|
||||
} else {
|
||||
const Scalar u_outer_slope_YX = unsigned_value(outer_slope_YX);
|
||||
if (u_slope_YX > u_outer_slope_YX) {
|
||||
update = true;
|
||||
} else if (u_slope_YX == u_outer_slope_YX &&
|
||||
slope_YX > outer_slope_YX) {
|
||||
update = true;
|
||||
} else if (slope_YX == outer_slope_YX) {
|
||||
const Scalar u_outer_slope_ZX =
|
||||
unsigned_value(outer_slope_ZX);
|
||||
if (u_slope_ZX > u_outer_slope_ZX) {
|
||||
update = true;
|
||||
} else if (u_slope_ZX == u_outer_slope_ZX &&
|
||||
slope_ZX > outer_slope_ZX) {
|
||||
update = true;
|
||||
} else if (slope_ZX == u_outer_slope_ZX) {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (update) {
|
||||
outer_opp_vid = opp_vid;
|
||||
outer_slope_YX = slope_YX;
|
||||
outer_slope_ZX = slope_ZX;
|
||||
incident_faces = {fid};
|
||||
}
|
||||
} else if (!infinite_slope_detected)
|
||||
{
|
||||
// Infinite slope
|
||||
outer_opp_vid = opp_vid;
|
||||
infinite_slope_detected = true;
|
||||
incident_faces = {fid};
|
||||
}
|
||||
};
|
||||
|
||||
const size_t num_candidate_faces = candidate_faces.size();
|
||||
for (size_t i=0; i<num_candidate_faces; i++)
|
||||
{
|
||||
const Index fid = candidate_faces(i);
|
||||
const IndexArray3& f = F.row(fid);
|
||||
size_t id = get_vertex_index(f, outer_vid);
|
||||
Index next_vid = f((id+1)%3);
|
||||
Index prev_vid = f((id+2)%3);
|
||||
check_and_update_outer_edge(next_vid, fid);
|
||||
check_and_update_outer_edge(prev_vid, fid);
|
||||
}
|
||||
|
||||
v1 = outer_vid;
|
||||
v2 = outer_opp_vid;
|
||||
A.resize(incident_faces.size());
|
||||
std::copy(incident_faces.begin(), incident_faces.end(), A.data());
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, long, Eigen::Matrix<long, -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&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 1, -1, -1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 1, -1, -1> > const&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, long, Eigen::Matrix<long, -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&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
|
||||
#ifdef WIN32
|
||||
template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<long, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<long, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, 3, 0, -1, 3>, class Eigen::Matrix<long, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<long, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<double, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<double, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<double, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 1, -1, -1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 1, -1, -1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<double, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, 3, 0, -1, 3>, class Eigen::Matrix<long, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<long, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
|
||||
#endif
|
||||
#endif
|
||||
83
src/igl/copyleft/cgal/outer_element.h
Normal file
83
src/igl/copyleft/cgal/outer_element.h
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 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_OUTER_ELEMENT_H
|
||||
#define IGL_COPYLEFT_CGAL_OUTER_ELEMENT_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Find a vertex that is reachable from infinite without crossing any faces.
|
||||
// Such vertex is called "outer vertex."
|
||||
//
|
||||
// Precondition: The input mesh must have all self-intersection resolved and
|
||||
// no duplicated vertices. See cgal::remesh_self_intersections.h for how to
|
||||
// obtain such input.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices into V
|
||||
// I #I list of facets to consider
|
||||
// Outputs:
|
||||
// v_index index of outer vertex
|
||||
// A #A list of facets incident to the outer vertex
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename IndexType,
|
||||
typename DerivedA
|
||||
>
|
||||
IGL_INLINE void outer_vertex(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
const Eigen::PlainObjectBase<DerivedI> & I,
|
||||
IndexType & v_index,
|
||||
Eigen::PlainObjectBase<DerivedA> & A);
|
||||
// Find an edge that is reachable from infinity without crossing any faces.
|
||||
// Such edge is called "outer edge."
|
||||
//
|
||||
// Precondition: The input mesh must have all self-intersection resolved
|
||||
// and no duplicated vertices. The correctness of the output depends on
|
||||
// the fact that there is no edge overlap. See
|
||||
// cgal::remesh_self_intersections.h for how to obtain such input.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices into V
|
||||
// I #I list of facets to consider
|
||||
// Outputs:
|
||||
// v1 index of the first end point of outer edge
|
||||
// v2 index of the second end point of outer edge
|
||||
// A #A list of facets incident to the outer edge
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename IndexType,
|
||||
typename DerivedA
|
||||
>
|
||||
IGL_INLINE void outer_edge(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
const Eigen::PlainObjectBase<DerivedI> & I,
|
||||
IndexType & v1,
|
||||
IndexType & v2,
|
||||
Eigen::PlainObjectBase<DerivedA> & A);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "outer_element.cpp"
|
||||
#endif
|
||||
#endif
|
||||
180
src/igl/copyleft/cgal/outer_facet.cpp
Normal file
180
src/igl/copyleft/cgal/outer_facet.cpp
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
// 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 "outer_facet.h"
|
||||
#include "outer_element.h"
|
||||
#include "order_facets_around_edge.h"
|
||||
#include <algorithm>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename IndexType
|
||||
>
|
||||
IGL_INLINE void igl::copyleft::cgal::outer_facet(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
const Eigen::PlainObjectBase<DerivedI> & I,
|
||||
IndexType & f,
|
||||
bool & flipped) {
|
||||
|
||||
// Algorithm:
|
||||
//
|
||||
// 1. Find an outer edge (s, d).
|
||||
//
|
||||
// 2. Order adjacent facets around this edge. Because the edge is an
|
||||
// outer edge, there exists a plane passing through it such that all its
|
||||
// adjacent facets lie on the same side. The implementation of
|
||||
// order_facets_around_edge() will find a natural start facet such that
|
||||
// The first and last facets according to this order are on the outside.
|
||||
//
|
||||
// 3. Because the vertex s is an outer vertex by construction (see
|
||||
// implemnetation of outer_edge()). The first adjacent facet is facing
|
||||
// outside (i.e. flipped=false) if it has positive X normal component.
|
||||
// If it has zero normal component, it is facing outside if it contains
|
||||
// directed edge (s, d).
|
||||
|
||||
//typedef typename DerivedV::Scalar Scalar;
|
||||
typedef typename DerivedV::Index Index;
|
||||
|
||||
Index s,d;
|
||||
Eigen::Matrix<Index,Eigen::Dynamic,1> incident_faces;
|
||||
outer_edge(V, F, I, s, d, incident_faces);
|
||||
assert(incident_faces.size() > 0);
|
||||
|
||||
auto convert_to_signed_index = [&](size_t fid) -> int{
|
||||
if ((F(fid, 0) == s && F(fid, 1) == d) ||
|
||||
(F(fid, 1) == s && F(fid, 2) == d) ||
|
||||
(F(fid, 2) == s && F(fid, 0) == d) ) {
|
||||
return int(fid+1) * -1;
|
||||
} else {
|
||||
return int(fid+1);
|
||||
}
|
||||
};
|
||||
|
||||
auto signed_index_to_index = [&](int signed_id) -> size_t {
|
||||
return size_t(abs(signed_id) - 1);
|
||||
};
|
||||
|
||||
std::vector<int> adj_faces(incident_faces.size());
|
||||
std::transform(incident_faces.data(),
|
||||
incident_faces.data() + incident_faces.size(),
|
||||
adj_faces.begin(),
|
||||
convert_to_signed_index);
|
||||
|
||||
DerivedV pivot_point = V.row(s);
|
||||
pivot_point(0, 0) += 1.0;
|
||||
|
||||
Eigen::VectorXi order;
|
||||
order_facets_around_edge(V, F, s, d, adj_faces, pivot_point, order);
|
||||
|
||||
f = signed_index_to_index(adj_faces[order[0]]);
|
||||
flipped = adj_faces[order[0]] > 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedN,
|
||||
typename DerivedI,
|
||||
typename IndexType
|
||||
>
|
||||
IGL_INLINE void igl::copyleft::cgal::outer_facet(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
const Eigen::PlainObjectBase<DerivedN> & N,
|
||||
const Eigen::PlainObjectBase<DerivedI> & I,
|
||||
IndexType & f,
|
||||
bool & flipped) {
|
||||
// Algorithm:
|
||||
// Find an outer edge.
|
||||
// Find the incident facet with the largest absolute X normal component.
|
||||
// If there is a tie, keep the one with positive X component.
|
||||
// If there is still a tie, pick the face with the larger signed index
|
||||
// (flipped face has negative index).
|
||||
typedef typename DerivedV::Scalar Scalar;
|
||||
typedef typename DerivedV::Index Index;
|
||||
const size_t INVALID = std::numeric_limits<size_t>::max();
|
||||
|
||||
Index v1,v2;
|
||||
Eigen::Matrix<Index,Eigen::Dynamic,1> incident_faces;
|
||||
outer_edge(V, F, I, v1, v2, incident_faces);
|
||||
assert(incident_faces.size() > 0);
|
||||
|
||||
auto generic_fabs = [&](const Scalar& val) -> const Scalar {
|
||||
if (val >= 0) return val;
|
||||
else return -val;
|
||||
};
|
||||
|
||||
Scalar max_nx = 0;
|
||||
size_t outer_fid = INVALID;
|
||||
const size_t num_incident_faces = incident_faces.size();
|
||||
for (size_t i=0; i<num_incident_faces; i++)
|
||||
{
|
||||
const auto& fid = incident_faces(i);
|
||||
const Scalar nx = N(fid, 0);
|
||||
if (outer_fid == INVALID) {
|
||||
max_nx = nx;
|
||||
outer_fid = fid;
|
||||
} else {
|
||||
if (generic_fabs(nx) > generic_fabs(max_nx)) {
|
||||
max_nx = nx;
|
||||
outer_fid = fid;
|
||||
} else if (nx == -max_nx && nx > 0) {
|
||||
max_nx = nx;
|
||||
outer_fid = fid;
|
||||
} else if (nx == max_nx) {
|
||||
if ((max_nx >= 0 && outer_fid < fid) ||
|
||||
(max_nx < 0 && outer_fid > fid)) {
|
||||
max_nx = nx;
|
||||
outer_fid = fid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(outer_fid != INVALID);
|
||||
f = outer_fid;
|
||||
flipped = max_nx < 0;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned long>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, unsigned long&, bool&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int&, bool&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned long>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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&, unsigned long&, bool&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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&, int&, bool&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned long>(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&, unsigned long&, bool&);
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
template void igl::copyleft::cgal::outer_facet<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::Matrix<long, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, int&, bool&);
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 1, -1, -1>, unsigned long>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 1, -1, -1> > const&, unsigned long&, bool&);
|
||||
template void igl::copyleft::cgal::outer_facet<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::Matrix<int, -1, 1, 0, -1, 1>, int>(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, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int&, bool&);
|
||||
template void igl::copyleft::cgal::outer_facet<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>, int>(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&, int&, bool&);
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, int&, bool&);
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, int&, bool&);
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(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&, int&, bool&);
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned long>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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&, unsigned long&, bool&);
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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&, int&, bool&);
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, int&, bool&);
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(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&, int&, bool&);
|
||||
#ifdef WIN32
|
||||
template void igl::copyleft::cgal::outer_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned __int64>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, unsigned __int64 &, bool &);
|
||||
template void igl::copyleft::cgal::outer_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned __int64>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, unsigned __int64 &, bool &);
|
||||
template void igl::copyleft::cgal::outer_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned __int64>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, unsigned __int64 &, bool &);
|
||||
#endif
|
||||
#endif
|
||||
91
src/igl/copyleft/cgal/outer_facet.h
Normal file
91
src/igl/copyleft/cgal/outer_facet.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
// 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_OUTER_FACET_H
|
||||
#define IGL_COPYLEFT_CGAL_OUTER_FACET_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Find a facet that is reachable from infinity without crossing any faces.
|
||||
// Such facet is called "outer facet."
|
||||
//
|
||||
// Precondition: The input mesh must have all self-intersection resolved. I.e
|
||||
// there is no duplicated vertices, no overlapping edge and no intersecting
|
||||
// faces (the only exception is there could be topologically duplicated faces).
|
||||
// See cgal::remesh_self_intersections.h for how to obtain such input.
|
||||
//
|
||||
// This function differ from igl::outer_facet() in the fact this
|
||||
// function is more robust because it does not rely on facet normals.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices into V
|
||||
// I #I list of facets to consider
|
||||
// Outputs:
|
||||
// f Index of the outer facet.
|
||||
// flipped true iff the normal of f points inwards.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename IndexType
|
||||
>
|
||||
IGL_INLINE void outer_facet(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
const Eigen::PlainObjectBase<DerivedI> & I,
|
||||
IndexType & f,
|
||||
bool & flipped);
|
||||
|
||||
// Find a facet that is reachable from infinity without crossing any faces.
|
||||
// Such facet is called "outer facet."
|
||||
//
|
||||
// Precondition: The input mesh must have all self-intersection resolved.
|
||||
// I.e there is no duplicated vertices, no overlapping edge and no
|
||||
// intersecting faces (the only exception is there could be topologically
|
||||
// duplicated faces). See cgal::remesh_self_intersections.h for how to
|
||||
// obtain such input.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices into V
|
||||
// N #N by 3 list of face normals
|
||||
// I #I list of facets to consider
|
||||
// Outputs:
|
||||
// f Index of the outer facet.
|
||||
// flipped true iff the normal of f points inwards.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedN,
|
||||
typename DerivedI,
|
||||
typename IndexType
|
||||
>
|
||||
IGL_INLINE void outer_facet(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
const Eigen::PlainObjectBase<DerivedN> & N,
|
||||
const Eigen::PlainObjectBase<DerivedI> & I,
|
||||
IndexType & f,
|
||||
bool & flipped);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "outer_facet.cpp"
|
||||
#endif
|
||||
#endif
|
||||
535
src/igl/copyleft/cgal/outer_hull.cpp
Normal file
535
src/igl/copyleft/cgal/outer_hull.cpp
Normal file
|
|
@ -0,0 +1,535 @@
|
|||
// 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 "outer_hull.h"
|
||||
#include "extract_cells.h"
|
||||
#include "remesh_self_intersections.h"
|
||||
#include "assign.h"
|
||||
#include "../../remove_unreferenced.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>
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedHV,
|
||||
typename DerivedHF,
|
||||
typename DerivedJ,
|
||||
typename Derivedflip>
|
||||
IGL_INLINE void igl::copyleft::cgal::outer_hull(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedHV> & HV,
|
||||
Eigen::PlainObjectBase<DerivedHF> & HF,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J,
|
||||
Eigen::PlainObjectBase<Derivedflip> & flip)
|
||||
{
|
||||
// Exact types
|
||||
typedef CGAL::Epeck Kernel;
|
||||
typedef Kernel::FT ExactScalar;
|
||||
typedef
|
||||
Eigen::Matrix<
|
||||
ExactScalar,
|
||||
Eigen::Dynamic,
|
||||
Eigen::Dynamic,
|
||||
DerivedHV::IsRowMajor>
|
||||
MatrixXES;
|
||||
// Remesh self-intersections
|
||||
MatrixXES Vr;
|
||||
DerivedHF Fr;
|
||||
DerivedJ Jr;
|
||||
{
|
||||
RemeshSelfIntersectionsParam params;
|
||||
params.stitch_all = true;
|
||||
Eigen::VectorXi I;
|
||||
Eigen::MatrixXi IF;
|
||||
remesh_self_intersections(V, F, params, Vr, Fr, IF, Jr, I);
|
||||
// Merge coinciding vertices into non-manifold vertices.
|
||||
std::for_each(Fr.data(), Fr.data()+Fr.size(),
|
||||
[&I](typename DerivedHF::Scalar& a) { a=I[a]; });
|
||||
// Remove unreferenced vertices.
|
||||
Eigen::VectorXi UIM;
|
||||
remove_unreferenced(MatrixXES(Vr),DerivedHF(Fr), Vr, Fr, UIM);
|
||||
}
|
||||
// Extract cells for each face
|
||||
Eigen::MatrixXi C;
|
||||
extract_cells(Vr,Fr,C);
|
||||
// Extract faces on ambient cell
|
||||
int num_outer = 0;
|
||||
for(int i = 0;i<C.rows();i++)
|
||||
{
|
||||
num_outer += ( C(i,0) == 0 || C(i,1) == 0 ) ? 1 : 0;
|
||||
}
|
||||
HF.resize(num_outer,3);
|
||||
J.resize(num_outer,1);
|
||||
flip.resize(num_outer,1);
|
||||
{
|
||||
int h = 0;
|
||||
for(int i = 0;i<C.rows();i++)
|
||||
{
|
||||
if(C(i,0)==0)
|
||||
{
|
||||
HF.row(h) = Fr.row(i);
|
||||
J(h) = Jr(i);
|
||||
flip(h) = false;
|
||||
h++;
|
||||
}else if(C(i,1) == 0)
|
||||
{
|
||||
HF.row(h) = Fr.row(i).reverse();
|
||||
J(h) = Jr(i);
|
||||
flip(h) = true;
|
||||
h++;
|
||||
}
|
||||
}
|
||||
assert(h == num_outer);
|
||||
}
|
||||
// Remove unreferenced vertices and re-index faces
|
||||
{
|
||||
// Cast to output type
|
||||
DerivedHV Vr_cast;
|
||||
assign(Vr,Vr_cast);
|
||||
Eigen::VectorXi I;
|
||||
remove_unreferenced(Vr_cast,DerivedHF(HF),HV,HF,I);
|
||||
}
|
||||
}
|
||||
|
||||
#include "points_inside_component.h"
|
||||
#include "order_facets_around_edges.h"
|
||||
#include "outer_facet.h"
|
||||
#include "../../sortrows.h"
|
||||
#include "../../facet_components.h"
|
||||
#include "../../winding_number.h"
|
||||
#include "../../triangle_triangle_adjacency.h"
|
||||
#include "../../unique_edge_map.h"
|
||||
#include "../../barycenter.h"
|
||||
#include "../../per_face_normals.h"
|
||||
#include "../../sort_angles.h"
|
||||
#include <Eigen/Geometry>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <iostream>
|
||||
#include <type_traits>
|
||||
#include <CGAL/number_utils.h>
|
||||
//#define IGL_OUTER_HULL_DEBUG
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedG,
|
||||
typename DerivedJ,
|
||||
typename Derivedflip>
|
||||
IGL_INLINE void igl::copyleft::cgal::outer_hull_legacy(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedG> & G,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J,
|
||||
Eigen::PlainObjectBase<Derivedflip> & flip)
|
||||
{
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
std::cerr << "Extracting outer hull" << std::endl;
|
||||
#endif
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
typedef typename DerivedF::Index Index;
|
||||
Matrix<Index,DerivedF::RowsAtCompileTime,1> C;
|
||||
typedef Matrix<typename DerivedV::Scalar,Dynamic,DerivedV::ColsAtCompileTime> MatrixXV;
|
||||
//typedef Matrix<typename DerivedF::Scalar,Dynamic,DerivedF::ColsAtCompileTime> MatrixXF;
|
||||
typedef Matrix<typename DerivedG::Scalar,Dynamic,DerivedG::ColsAtCompileTime> MatrixXG;
|
||||
typedef Matrix<typename DerivedJ::Scalar,Dynamic,DerivedJ::ColsAtCompileTime> MatrixXJ;
|
||||
const Index m = F.rows();
|
||||
|
||||
// UNUSED:
|
||||
//const auto & duplicate_simplex = [&F](const int f, const int g)->bool
|
||||
//{
|
||||
// return
|
||||
// (F(f,0) == F(g,0) && F(f,1) == F(g,1) && F(f,2) == F(g,2)) ||
|
||||
// (F(f,1) == F(g,0) && F(f,2) == F(g,1) && F(f,0) == F(g,2)) ||
|
||||
// (F(f,2) == F(g,0) && F(f,0) == F(g,1) && F(f,1) == F(g,2)) ||
|
||||
// (F(f,0) == F(g,2) && F(f,1) == F(g,1) && F(f,2) == F(g,0)) ||
|
||||
// (F(f,1) == F(g,2) && F(f,2) == F(g,1) && F(f,0) == F(g,0)) ||
|
||||
// (F(f,2) == F(g,2) && F(f,0) == F(g,1) && F(f,1) == F(g,0));
|
||||
//};
|
||||
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
cout<<"outer hull..."<<endl;
|
||||
#endif
|
||||
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
cout<<"edge map..."<<endl;
|
||||
#endif
|
||||
typedef Matrix<typename DerivedF::Scalar,Dynamic,2> MatrixX2I;
|
||||
typedef Matrix<typename DerivedF::Index,Dynamic,1> VectorXI;
|
||||
//typedef Matrix<typename DerivedV::Scalar, 3, 1> Vector3F;
|
||||
MatrixX2I E,uE;
|
||||
VectorXI EMAP;
|
||||
vector<vector<typename DerivedF::Index> > uE2E;
|
||||
unique_edge_map(F,E,uE,EMAP,uE2E);
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
for (size_t ui=0; ui<uE.rows(); ui++) {
|
||||
std::cout << ui << ": " << uE2E[ui].size() << " -- (";
|
||||
for (size_t i=0; i<uE2E[ui].size(); i++) {
|
||||
std::cout << uE2E[ui][i] << ", ";
|
||||
}
|
||||
std::cout << ")" << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::vector<std::vector<typename DerivedF::Index> > uE2oE;
|
||||
std::vector<std::vector<bool> > uE2C;
|
||||
order_facets_around_edges(V, F, uE, uE2E, uE2oE, uE2C);
|
||||
uE2E = uE2oE;
|
||||
VectorXI diIM(3*m);
|
||||
for (auto ue : uE2E) {
|
||||
for (size_t i=0; i<ue.size(); i++) {
|
||||
auto fe = ue[i];
|
||||
diIM[fe] = i;
|
||||
}
|
||||
}
|
||||
|
||||
vector<vector<vector<Index > > > TT,_1;
|
||||
triangle_triangle_adjacency(E,EMAP,uE2E,false,TT,_1);
|
||||
VectorXI counts;
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
cout<<"facet components..."<<endl;
|
||||
#endif
|
||||
facet_components(TT,C,counts);
|
||||
assert(C.maxCoeff()+1 == counts.rows());
|
||||
const size_t ncc = counts.rows();
|
||||
G.resize(0,F.cols());
|
||||
J.resize(0,1);
|
||||
flip.setConstant(m,1,false);
|
||||
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
cout<<"reindex..."<<endl;
|
||||
#endif
|
||||
// H contains list of faces on outer hull;
|
||||
vector<bool> FH(m,false);
|
||||
vector<bool> EH(3*m,false);
|
||||
vector<MatrixXG> vG(ncc);
|
||||
vector<MatrixXJ> vJ(ncc);
|
||||
vector<MatrixXJ> vIM(ncc);
|
||||
//size_t face_count = 0;
|
||||
for(size_t id = 0;id<ncc;id++)
|
||||
{
|
||||
vIM[id].resize(counts[id],1);
|
||||
}
|
||||
// current index into each IM
|
||||
vector<size_t> g(ncc,0);
|
||||
// place order of each face in its respective component
|
||||
for(Index f = 0;f<m;f++)
|
||||
{
|
||||
vIM[C(f)](g[C(f)]++) = f;
|
||||
}
|
||||
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
cout<<"barycenters..."<<endl;
|
||||
#endif
|
||||
// assumes that "resolve" has handled any coplanar cases correctly and nearly
|
||||
// coplanar cases can be sorted based on barycenter.
|
||||
MatrixXV BC;
|
||||
barycenter(V,F,BC);
|
||||
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
cout<<"loop over CCs (="<<ncc<<")..."<<endl;
|
||||
#endif
|
||||
for(Index id = 0;id<(Index)ncc;id++)
|
||||
{
|
||||
auto & IM = vIM[id];
|
||||
// starting face that's guaranteed to be on the outer hull and in this
|
||||
// component
|
||||
int f;
|
||||
bool f_flip;
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
cout<<"outer facet..."<<endl;
|
||||
#endif
|
||||
igl::copyleft::cgal::outer_facet(V,F,IM,f,f_flip);
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
cout<<"outer facet: "<<f<<endl;
|
||||
//cout << V.row(F(f, 0)) << std::endl;
|
||||
//cout << V.row(F(f, 1)) << std::endl;
|
||||
//cout << V.row(F(f, 2)) << std::endl;
|
||||
#endif
|
||||
int FHcount = 1;
|
||||
FH[f] = true;
|
||||
// Q contains list of face edges to continue traversing upong
|
||||
queue<int> Q;
|
||||
Q.push(f+0*m);
|
||||
Q.push(f+1*m);
|
||||
Q.push(f+2*m);
|
||||
flip(f) = f_flip;
|
||||
//std::cout << "face " << face_count++ << ": " << f << std::endl;
|
||||
//std::cout << "f " << F.row(f).array()+1 << std::endl;
|
||||
//cout<<"flip("<<f<<") = "<<(flip(f)?"true":"false")<<endl;
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
cout<<"BFS..."<<endl;
|
||||
#endif
|
||||
while(!Q.empty())
|
||||
{
|
||||
// face-edge
|
||||
const int e = Q.front();
|
||||
Q.pop();
|
||||
// face
|
||||
const int f = e%m;
|
||||
// corner
|
||||
const int c = e/m;
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
std::cout << "edge: " << e << ", ue: " << EMAP(e) << std::endl;
|
||||
std::cout << "face: " << f << std::endl;
|
||||
std::cout << "corner: " << c << std::endl;
|
||||
std::cout << "consistent: " << uE2C[EMAP(e)][diIM[e]] << std::endl;
|
||||
#endif
|
||||
// Should never see edge again...
|
||||
if(EH[e] == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
EH[e] = true;
|
||||
// source of edge according to f
|
||||
const int fs = flip(f)?F(f,(c+2)%3):F(f,(c+1)%3);
|
||||
// destination of edge according to f
|
||||
const int fd = flip(f)?F(f,(c+1)%3):F(f,(c+2)%3);
|
||||
// edge valence
|
||||
const size_t val = uE2E[EMAP(e)].size();
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
//std::cout << "vd: " << V.row(fd) << std::endl;
|
||||
//std::cout << "vs: " << V.row(fs) << std::endl;
|
||||
//std::cout << "edge: " << V.row(fd) - V.row(fs) << std::endl;
|
||||
for (size_t i=0; i<val; i++) {
|
||||
if (i == diIM(e)) {
|
||||
std::cout << "* ";
|
||||
} else {
|
||||
std::cout << " ";
|
||||
}
|
||||
std::cout << i << ": "
|
||||
<< " (e: " << uE2E[EMAP(e)][i] << ", f: "
|
||||
<< uE2E[EMAP(e)][i] % m * (uE2C[EMAP(e)][i] ? 1:-1) << ")" << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
// is edge consistent with edge of face used for sorting
|
||||
const int e_cons = (uE2C[EMAP(e)][diIM(e)] ? 1: -1);
|
||||
int nfei = -1;
|
||||
// Loop once around trying to find suitable next face
|
||||
for(size_t step = 1; step<val+2;step++)
|
||||
{
|
||||
const int nfei_new = (diIM(e) + 2*val + e_cons*step*(flip(f)?-1:1))%val;
|
||||
const int nf = uE2E[EMAP(e)][nfei_new] % m;
|
||||
{
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
//cout<<"Next facet: "<<(f+1)<<" --> "<<(nf+1)<<", |"<<
|
||||
// di[EMAP(e)][diIM(e)]<<" - "<<di[EMAP(e)][nfei_new]<<"| = "<<
|
||||
// abs(di[EMAP(e)][diIM(e)] - di[EMAP(e)][nfei_new])
|
||||
// <<endl;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Only use this face if not already seen
|
||||
if(!FH[nf])
|
||||
{
|
||||
nfei = nfei_new;
|
||||
//} else {
|
||||
// std::cout << "skipping face " << nfei_new << " because it is seen before"
|
||||
// << std::endl;
|
||||
}
|
||||
break;
|
||||
//} else {
|
||||
// std::cout << di[EMAP(e)][diIM(e)].transpose() << std::endl;
|
||||
// std::cout << di[EMAP(e)][diIM(nfei_new)].transpose() << std::endl;
|
||||
// std::cout << "skipping face " << nfei_new << " with identical dihedral angle"
|
||||
// << std::endl;
|
||||
}
|
||||
//#ifdef IGL_OUTER_HULL_DEBUG
|
||||
// cout<<"Skipping co-planar facet: "<<(f+1)<<" --> "<<(nf+1)<<endl;
|
||||
//#endif
|
||||
}
|
||||
|
||||
int max_ne = -1;
|
||||
if(nfei >= 0)
|
||||
{
|
||||
max_ne = uE2E[EMAP(e)][nfei];
|
||||
}
|
||||
|
||||
if(max_ne>=0)
|
||||
{
|
||||
// face of neighbor
|
||||
const int nf = max_ne%m;
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
if(!FH[nf])
|
||||
{
|
||||
// first time seeing face
|
||||
cout<<(f+1)<<" --> "<<(nf+1)<<endl;
|
||||
}
|
||||
#endif
|
||||
FH[nf] = true;
|
||||
//std::cout << "face " << face_count++ << ": " << nf << std::endl;
|
||||
//std::cout << "f " << F.row(nf).array()+1 << std::endl;
|
||||
FHcount++;
|
||||
// corner of neighbor
|
||||
const int nc = max_ne/m;
|
||||
const int nd = F(nf,(nc+2)%3);
|
||||
const bool cons = (flip(f)?fd:fs) == nd;
|
||||
flip(nf) = (cons ? flip(f) : !flip(f));
|
||||
//cout<<"flip("<<nf<<") = "<<(flip(nf)?"true":"false")<<endl;
|
||||
const int ne1 = nf+((nc+1)%3)*m;
|
||||
const int ne2 = nf+((nc+2)%3)*m;
|
||||
if(!EH[ne1])
|
||||
{
|
||||
Q.push(ne1);
|
||||
}
|
||||
if(!EH[ne2])
|
||||
{
|
||||
Q.push(ne2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
vG[id].resize(FHcount,3);
|
||||
vJ[id].resize(FHcount,1);
|
||||
//nG += FHcount;
|
||||
size_t h = 0;
|
||||
assert(counts(id) == IM.rows());
|
||||
for(int i = 0;i<counts(id);i++)
|
||||
{
|
||||
const size_t f = IM(i);
|
||||
//if(f_flip)
|
||||
//{
|
||||
// flip(f) = !flip(f);
|
||||
//}
|
||||
if(FH[f])
|
||||
{
|
||||
vG[id].row(h) = (flip(f)?F.row(f).reverse().eval():F.row(f));
|
||||
vJ[id](h,0) = f;
|
||||
h++;
|
||||
}
|
||||
}
|
||||
assert((int)h == FHcount);
|
||||
}
|
||||
}
|
||||
|
||||
// Is A inside B? Assuming A and B are consistently oriented but closed and
|
||||
// non-intersecting.
|
||||
const auto & has_overlapping_bbox = [](
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const MatrixXG & A,
|
||||
const MatrixXG & B)->bool
|
||||
{
|
||||
const auto & bounding_box = [](
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const MatrixXG & F)->
|
||||
DerivedV
|
||||
{
|
||||
DerivedV BB(2,3);
|
||||
BB<<
|
||||
1e26,1e26,1e26,
|
||||
-1e26,-1e26,-1e26;
|
||||
const size_t m = F.rows();
|
||||
for(size_t f = 0;f<m;f++)
|
||||
{
|
||||
for(size_t c = 0;c<3;c++)
|
||||
{
|
||||
const auto & vfc = V.row(F(f,c)).eval();
|
||||
BB(0,0) = std::min(BB(0,0), vfc(0,0));
|
||||
BB(0,1) = std::min(BB(0,1), vfc(0,1));
|
||||
BB(0,2) = std::min(BB(0,2), vfc(0,2));
|
||||
BB(1,0) = std::max(BB(1,0), vfc(0,0));
|
||||
BB(1,1) = std::max(BB(1,1), vfc(0,1));
|
||||
BB(1,2) = std::max(BB(1,2), vfc(0,2));
|
||||
}
|
||||
}
|
||||
return BB;
|
||||
};
|
||||
// A lot of the time we're dealing with unrelated, distant components: cull
|
||||
// them.
|
||||
DerivedV ABB = bounding_box(V,A);
|
||||
DerivedV BBB = bounding_box(V,B);
|
||||
if( (BBB.row(0)-ABB.row(1)).maxCoeff()>0 ||
|
||||
(ABB.row(0)-BBB.row(1)).maxCoeff()>0 )
|
||||
{
|
||||
// bounding boxes do not overlap
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Reject components which are completely inside other components
|
||||
vector<bool> keep(ncc,true);
|
||||
size_t nG = 0;
|
||||
// This is O( ncc * ncc * m)
|
||||
for(size_t id = 0;id<ncc;id++)
|
||||
{
|
||||
if (!keep[id]) continue;
|
||||
std::vector<size_t> unresolved;
|
||||
for(size_t oid = 0;oid<ncc;oid++)
|
||||
{
|
||||
if(id == oid || !keep[oid])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (has_overlapping_bbox(V, vG[id], vG[oid])) {
|
||||
unresolved.push_back(oid);
|
||||
}
|
||||
}
|
||||
const size_t num_unresolved_components = unresolved.size();
|
||||
DerivedV query_points(num_unresolved_components, 3);
|
||||
for (size_t i=0; i<num_unresolved_components; i++) {
|
||||
const size_t oid = unresolved[i];
|
||||
DerivedF f = vG[oid].row(0);
|
||||
query_points(i,0) = (V(f(0,0), 0) + V(f(0,1), 0) + V(f(0,2), 0))/3.0;
|
||||
query_points(i,1) = (V(f(0,0), 1) + V(f(0,1), 1) + V(f(0,2), 1))/3.0;
|
||||
query_points(i,2) = (V(f(0,0), 2) + V(f(0,1), 2) + V(f(0,2), 2))/3.0;
|
||||
}
|
||||
Eigen::VectorXi inside;
|
||||
igl::copyleft::cgal::points_inside_component(V, vG[id], query_points, inside);
|
||||
assert((size_t)inside.size() == num_unresolved_components);
|
||||
for (size_t i=0; i<num_unresolved_components; i++) {
|
||||
if (inside(i, 0)) {
|
||||
const size_t oid = unresolved[i];
|
||||
keep[oid] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (size_t id = 0; id<ncc; id++) {
|
||||
if (keep[id]) {
|
||||
nG += vJ[id].rows();
|
||||
}
|
||||
}
|
||||
|
||||
// collect G and J across components
|
||||
G.resize(nG,3);
|
||||
J.resize(nG,1);
|
||||
{
|
||||
size_t off = 0;
|
||||
for(Index id = 0;id<(Index)ncc;id++)
|
||||
{
|
||||
if(keep[id])
|
||||
{
|
||||
assert(vG[id].rows() == vJ[id].rows());
|
||||
G.block(off,0,vG[id].rows(),vG[id].cols()) = vG[id];
|
||||
J.block(off,0,vJ[id].rows(),vJ[id].cols()) = vJ[id];
|
||||
off += vG[id].rows();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::copyleft::cgal::outer_hull<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<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<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::outer_hull_legacy< Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::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> > &, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > &, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > &);
|
||||
template void igl::copyleft::cgal::outer_hull_legacy< Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::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> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::outer_hull_legacy<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::outer_hull_legacy<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
84
src/igl/copyleft/cgal/outer_hull.h
Normal file
84
src/igl/copyleft/cgal/outer_hull.h
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
// 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_OUTER_HULL_H
|
||||
#define IGL_COPYLEFT_CGAL_OUTER_HULL_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Compute the "outer hull" of a piecewise constant winding number induce
|
||||
// triangle mesh (V,F).
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices into V
|
||||
// Outputs:
|
||||
// HV #HV by 3 list of output vertex positions
|
||||
// HF #HF by 3 list of output triangle indices into HV
|
||||
// J #HF list of indices into F
|
||||
// flip #HF list of whether facet was flipped when added to HF
|
||||
//
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedHV,
|
||||
typename DerivedHF,
|
||||
typename DerivedJ,
|
||||
typename Derivedflip>
|
||||
IGL_INLINE void outer_hull(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedHV> & HV,
|
||||
Eigen::PlainObjectBase<DerivedHF> & HF,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J,
|
||||
Eigen::PlainObjectBase<Derivedflip> & flip);
|
||||
// Compute the "outer hull" of a potentially non-manifold mesh (V,F) whose
|
||||
// intersections have been "resolved" (e.g. using `cork` or
|
||||
// `igl::copyleft::cgal::selfintersect`). The outer hull is defined to be all facets
|
||||
// (regardless of orientation) for which there exists some path from infinity
|
||||
// to the face without intersecting any other facets. For solids, this is the
|
||||
// surface of the solid. In general this includes any thin "wings" or
|
||||
// "flaps". This implementation largely follows Section 3.6 of "Direct
|
||||
// repair of self-intersecting meshes" [Attene 2014].
|
||||
//
|
||||
// Note: This doesn't require the input mesh to be piecewise constant
|
||||
// winding number, but won't handle multiple non-nested connected
|
||||
// components.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices into V
|
||||
// Outputs:
|
||||
// G #G by 3 list of output triangle indices into V
|
||||
// J #G list of indices into F
|
||||
// flip #F list of whether facet was added to G **and** flipped orientation
|
||||
// (false for faces not added to G)
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedG,
|
||||
typename DerivedJ,
|
||||
typename Derivedflip>
|
||||
IGL_INLINE void outer_hull_legacy(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedG> & G,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J,
|
||||
Eigen::PlainObjectBase<Derivedflip> & flip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "outer_hull.cpp"
|
||||
#endif
|
||||
#endif
|
||||
124
src/igl/copyleft/cgal/peel_outer_hull_layers.cpp
Normal file
124
src/igl/copyleft/cgal/peel_outer_hull_layers.cpp
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
// 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 "peel_outer_hull_layers.h"
|
||||
#include "outer_hull.h"
|
||||
#include "../../LinSpaced.h"
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
//#define IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
|
||||
#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
|
||||
#include "../../writePLY.h"
|
||||
#include "../../writeDMAT.h"
|
||||
#include "../../STR.h"
|
||||
#endif
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename Derivedflip>
|
||||
IGL_INLINE size_t igl::copyleft::cgal::peel_outer_hull_layers(
|
||||
const Eigen::PlainObjectBase<DerivedV > & V,
|
||||
const Eigen::PlainObjectBase<DerivedF > & F,
|
||||
Eigen::PlainObjectBase<DerivedI> & I,
|
||||
Eigen::PlainObjectBase<Derivedflip > & flip)
|
||||
{
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
typedef typename DerivedF::Index Index;
|
||||
typedef Matrix<typename DerivedF::Scalar,Dynamic,DerivedF::ColsAtCompileTime> MatrixXF;
|
||||
typedef Matrix<Index,Dynamic,1> MatrixXI;
|
||||
typedef Matrix<typename Derivedflip::Scalar,Dynamic,Derivedflip::ColsAtCompileTime> MatrixXflip;
|
||||
const Index m = F.rows();
|
||||
#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
|
||||
cout<<"peel outer hull layers..."<<endl;
|
||||
#endif
|
||||
#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
|
||||
cout<<"calling outer hull..."<<endl;
|
||||
writePLY(STR("peel-outer-hull-input.ply"),V,F);
|
||||
#endif
|
||||
|
||||
#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
|
||||
cout<<"resize output ..."<<endl;
|
||||
#endif
|
||||
// keep track of iteration parity and whether flipped in hull
|
||||
MatrixXF Fr = F;
|
||||
I.resize(m,1);
|
||||
flip.resize(m,1);
|
||||
// Keep track of index map
|
||||
MatrixXI IM = igl::LinSpaced<MatrixXI >(m,0,m-1);
|
||||
// This is O(n * layers)
|
||||
MatrixXI P(m,1);
|
||||
Index iter = 0;
|
||||
while(Fr.size() > 0)
|
||||
{
|
||||
assert(Fr.rows() == IM.rows());
|
||||
// Compute outer hull of current Fr
|
||||
MatrixXF Fo;
|
||||
MatrixXI Jo;
|
||||
MatrixXflip flipr;
|
||||
#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
|
||||
{
|
||||
cout<<"calling outer hull..." << iter <<endl;
|
||||
std::stringstream ss;
|
||||
ss << "outer_hull_" << iter << ".ply";
|
||||
Eigen::MatrixXd vertices(V.rows(), V.cols());
|
||||
std::transform(V.data(), V.data() + V.rows()*V.cols(),
|
||||
vertices.data(),
|
||||
[](typename DerivedV::Scalar val)
|
||||
{return CGAL::to_double(val); });
|
||||
writePLY(ss.str(), vertices, Fr);
|
||||
}
|
||||
#endif
|
||||
outer_hull_legacy(V,Fr,Fo,Jo,flipr);
|
||||
#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
|
||||
writePLY(STR("outer-hull-output-"<<iter<<".ply"),V,Fo);
|
||||
cout<<"reindex, flip..."<<endl;
|
||||
#endif
|
||||
assert(Fo.rows() != 0);
|
||||
assert(Fo.rows() == Jo.rows());
|
||||
// all faces in Fo of Fr
|
||||
vector<bool> in_outer(Fr.rows(),false);
|
||||
for(Index g = 0;g<Jo.rows();g++)
|
||||
{
|
||||
I(IM(Jo(g))) = iter;
|
||||
P(IM(Jo(g))) = iter;
|
||||
in_outer[Jo(g)] = true;
|
||||
flip(IM(Jo(g))) = flipr(Jo(g));
|
||||
}
|
||||
// Fr = Fr - Fo
|
||||
// update IM
|
||||
MatrixXF prev_Fr = Fr;
|
||||
MatrixXI prev_IM = IM;
|
||||
Fr.resize(prev_Fr.rows() - Fo.rows(),F.cols());
|
||||
IM.resize(Fr.rows());
|
||||
{
|
||||
Index g = 0;
|
||||
for(Index f = 0;f<prev_Fr.rows();f++)
|
||||
{
|
||||
if(!in_outer[f])
|
||||
{
|
||||
Fr.row(g) = prev_Fr.row(f);
|
||||
IM(g) = prev_IM(f);
|
||||
g++;
|
||||
}
|
||||
}
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
return iter;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
template unsigned long igl::copyleft::cgal::peel_outer_hull_layers<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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::Lazy_exact_nt<CGAL::Gmpq>, -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> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template size_t igl::copyleft::cgal::peel_outer_hull_layers<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
47
src/igl/copyleft/cgal/peel_outer_hull_layers.h
Normal file
47
src/igl/copyleft/cgal/peel_outer_hull_layers.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// 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_PEEL_OUTER_HULL_LAYERS_H
|
||||
#define IGL_COPYLEFT_CGAL_PEEL_OUTER_HULL_LAYERS_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Computes necessary generic information for boolean operations by
|
||||
// successively "peeling" off the "outer hull" of a mesh (V,F) resulting from
|
||||
// "resolving" all (self-)intersections.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices into V
|
||||
// Outputs:
|
||||
// I #F list of which peel Iation a facet belongs
|
||||
// flip #F list of whether a facet's orientation was flipped when facet
|
||||
// "peeled" into its associated outer hull layer.
|
||||
// Returns number of peels
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename Derivedflip>
|
||||
IGL_INLINE size_t peel_outer_hull_layers(
|
||||
const Eigen::PlainObjectBase<DerivedV > & V,
|
||||
const Eigen::PlainObjectBase<DerivedF > & F,
|
||||
Eigen::PlainObjectBase<DerivedI > & I,
|
||||
Eigen::PlainObjectBase<Derivedflip > & flip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "peel_outer_hull_layers.cpp"
|
||||
#endif
|
||||
#endif
|
||||
33
src/igl/copyleft/cgal/peel_winding_number_layers.cpp
Normal file
33
src/igl/copyleft/cgal/peel_winding_number_layers.cpp
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#include "peel_winding_number_layers.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "propagate_winding_numbers.h"
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedW >
|
||||
IGL_INLINE size_t igl::copyleft::cgal::peel_winding_number_layers(
|
||||
const Eigen::PlainObjectBase<DerivedV > & V,
|
||||
const Eigen::PlainObjectBase<DerivedF > & F,
|
||||
Eigen::PlainObjectBase<DerivedW>& W) {
|
||||
const size_t num_faces = F.rows();
|
||||
Eigen::VectorXi labels(num_faces);
|
||||
labels.setZero();
|
||||
|
||||
Eigen::MatrixXi winding_numbers;
|
||||
igl::copyleft::cgal::propagate_winding_numbers(V, F, labels, winding_numbers);
|
||||
assert(winding_numbers.rows() == num_faces);
|
||||
assert(winding_numbers.cols() == 2);
|
||||
|
||||
int min_w = winding_numbers.minCoeff();
|
||||
int max_w = winding_numbers.maxCoeff();
|
||||
assert(max_w > min_w);
|
||||
|
||||
W.resize(num_faces, 1);
|
||||
for (size_t i=0; i<num_faces; i++) {
|
||||
W(i, 0) = winding_numbers(i, 1);
|
||||
}
|
||||
return max_w - min_w;
|
||||
}
|
||||
24
src/igl/copyleft/cgal/peel_winding_number_layers.h
Normal file
24
src/igl/copyleft/cgal/peel_winding_number_layers.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef IGL_COPYLEFT_CGAL_PEEL_WINDING_NUMBER_LAYERS_H
|
||||
#define IGL_COPYLEFT_CGAL_PEEL_WINDING_NUMBER_LAYERS_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl {
|
||||
namespace copyleft {
|
||||
namespace cgal {
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedW >
|
||||
IGL_INLINE size_t peel_winding_number_layers(
|
||||
const Eigen::PlainObjectBase<DerivedV > & V,
|
||||
const Eigen::PlainObjectBase<DerivedF > & F,
|
||||
Eigen::PlainObjectBase<DerivedW>& W);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "peel_winding_number_layers.cpp"
|
||||
#endif
|
||||
#endif
|
||||
27
src/igl/copyleft/cgal/piecewise_constant_winding_number.cpp
Normal file
27
src/igl/copyleft/cgal/piecewise_constant_winding_number.cpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson
|
||||
//
|
||||
// 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 "piecewise_constant_winding_number.h"
|
||||
#include "../../piecewise_constant_winding_number.h"
|
||||
#include "remesh_self_intersections.h"
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <algorithm>
|
||||
|
||||
template < typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE bool igl::copyleft::cgal::piecewise_constant_winding_number(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F)
|
||||
{
|
||||
Eigen::Matrix<CGAL::Epeck::FT,Eigen::Dynamic,3> VV;
|
||||
Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,3> FF;
|
||||
Eigen::Matrix<typename DerivedF::Index,Eigen::Dynamic,2> IF;
|
||||
Eigen::Matrix<typename DerivedF::Index,Eigen::Dynamic,1> J;
|
||||
Eigen::Matrix<typename DerivedV::Index,Eigen::Dynamic,1> UIM,IM;
|
||||
// resolve intersections
|
||||
remesh_self_intersections(V,F,{false,false,true},VV,FF,IF,J,IM);
|
||||
return igl::piecewise_constant_winding_number(FF);
|
||||
}
|
||||
41
src/igl/copyleft/cgal/piecewise_constant_winding_number.h
Normal file
41
src/igl/copyleft/cgal/piecewise_constant_winding_number.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson
|
||||
//
|
||||
// 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_PIECEWISE_CONSTANT_WINDING_NUMBER_H
|
||||
#define IGL_COPYLEFT_CGAL_PIECEWISE_CONSTANT_WINDING_NUMBER_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// PIECEWISE_CONSTANT_WINDING_NUMBER Determine if a given mesh induces a
|
||||
// piecewise constant winding number field: Is this mesh valid input to
|
||||
// solid set operations.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of mesh vertex positions
|
||||
// F #F by 3 list of triangle indices into V
|
||||
// Returns true if the mesh _combinatorially_ induces a piecewise
|
||||
// constant winding number field.
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF>
|
||||
IGL_INLINE bool piecewise_constant_winding_number(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "piecewise_constant_winding_number.cpp"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
181
src/igl/copyleft/cgal/point_areas.cpp
Normal file
181
src/igl/copyleft/cgal/point_areas.cpp
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
#include "point_areas.h"
|
||||
#include "delaunay_triangulation.h"
|
||||
|
||||
#include "../../colon.h"
|
||||
#include "../../slice.h"
|
||||
#include "../../slice_mask.h"
|
||||
#include "../../parallel_for.h"
|
||||
|
||||
#include "CGAL/Exact_predicates_inexact_constructions_kernel.h"
|
||||
#include "CGAL/Triangulation_vertex_base_with_info_2.h"
|
||||
#include "CGAL/Triangulation_data_structure_2.h"
|
||||
#include "CGAL/Delaunay_triangulation_2.h"
|
||||
|
||||
|
||||
|
||||
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;
|
||||
|
||||
namespace igl {
|
||||
namespace copyleft{
|
||||
namespace cgal{
|
||||
|
||||
template <typename DerivedP, typename DerivedI, typename DerivedN,
|
||||
typename DerivedA>
|
||||
IGL_INLINE void point_areas(
|
||||
const Eigen::MatrixBase<DerivedP>& P,
|
||||
const Eigen::MatrixBase<DerivedI>& I,
|
||||
const Eigen::MatrixBase<DerivedN>& N,
|
||||
Eigen::PlainObjectBase<DerivedA> & A)
|
||||
{
|
||||
Eigen::MatrixXd T;
|
||||
point_areas(P,I,N,A,T);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedP, typename DerivedI, typename DerivedN,
|
||||
typename DerivedA, typename DerivedT>
|
||||
IGL_INLINE void point_areas(
|
||||
const Eigen::MatrixBase<DerivedP>& P,
|
||||
const Eigen::MatrixBase<DerivedI>& I,
|
||||
const Eigen::MatrixBase<DerivedN>& N,
|
||||
Eigen::PlainObjectBase<DerivedA> & A,
|
||||
Eigen::PlainObjectBase<DerivedT> & T)
|
||||
{
|
||||
typedef typename DerivedP::Scalar real;
|
||||
typedef typename DerivedN::Scalar scalarN;
|
||||
typedef typename DerivedA::Scalar scalarA;
|
||||
typedef Eigen::Matrix<real,1,3> RowVec3;
|
||||
typedef Eigen::Matrix<real,1,2> RowVec2;
|
||||
|
||||
typedef Eigen::Matrix<real, Eigen::Dynamic, Eigen::Dynamic> MatrixP;
|
||||
typedef Eigen::Matrix<scalarN, Eigen::Dynamic, Eigen::Dynamic> MatrixN;
|
||||
typedef Eigen::Matrix<typename DerivedN::Scalar,
|
||||
Eigen::Dynamic, Eigen::Dynamic> VecotorO;
|
||||
typedef Eigen::Matrix<typename DerivedI::Scalar,
|
||||
Eigen::Dynamic, Eigen::Dynamic> MatrixI;
|
||||
|
||||
|
||||
|
||||
const int n = P.rows();
|
||||
|
||||
assert(P.cols() == 3 && "P must have exactly 3 columns");
|
||||
assert(P.rows() == N.rows()
|
||||
&& "P and N must have the same number of rows");
|
||||
assert(P.rows() == I.rows()
|
||||
&& "P and I must have the same number of rows");
|
||||
|
||||
A.setZero(n,1);
|
||||
T.setZero(n,3);
|
||||
igl::parallel_for(P.rows(),[&](int i)
|
||||
{
|
||||
MatrixI neighbor_index = I.row(i);
|
||||
MatrixP neighbors;
|
||||
igl::slice(P,neighbor_index,1,neighbors);
|
||||
if(N.rows() && neighbors.rows() > 1){
|
||||
MatrixN neighbor_normals;
|
||||
igl::slice(N,neighbor_index,1,neighbor_normals);
|
||||
Eigen::Matrix<scalarN,1,3> poi_normal = neighbor_normals.row(0);
|
||||
Eigen::Matrix<scalarN,Eigen::Dynamic,1> dotprod =
|
||||
poi_normal(0)*neighbor_normals.col(0)
|
||||
+ poi_normal(1)*neighbor_normals.col(1)
|
||||
+ poi_normal(2)*neighbor_normals.col(2);
|
||||
Eigen::Array<bool,Eigen::Dynamic,1> keep = dotprod.array() > 0;
|
||||
igl::slice_mask(Eigen::MatrixXd(neighbors),keep,1,neighbors);
|
||||
}
|
||||
if(neighbors.rows() <= 2){
|
||||
A(i) = 0;
|
||||
} else {
|
||||
//subtract the mean from neighbors, then take svd,
|
||||
//the scores will be U*S. This is our pca plane fitting
|
||||
RowVec3 mean = neighbors.colwise().mean();
|
||||
MatrixP mean_centered = neighbors.rowwise() - mean;
|
||||
Eigen::JacobiSVD<MatrixP> svd(mean_centered,
|
||||
Eigen::ComputeThinU | Eigen::ComputeThinV);
|
||||
MatrixP scores = svd.matrixU() * svd.singularValues().asDiagonal();
|
||||
|
||||
T.row(i) = svd.matrixV().col(2).transpose();
|
||||
if(T.row(i).dot(N.row(i)) < 0){
|
||||
T.row(i) *= -1;
|
||||
}
|
||||
|
||||
MatrixP plane;
|
||||
igl::slice(scores,igl::colon<int>(0,scores.rows()-1),
|
||||
igl::colon<int>(0,1),plane);
|
||||
|
||||
std::vector< std::pair<Point,unsigned> > points;
|
||||
//This is where we obtain a delaunay triangulation of the points
|
||||
for(unsigned iter = 0; iter < plane.rows(); iter++){
|
||||
points.push_back( std::make_pair(
|
||||
Point(plane(iter,0),plane(iter,1)), iter ) );
|
||||
}
|
||||
Delaunay triangulation;
|
||||
triangulation.insert(points.begin(),points.end());
|
||||
Eigen::MatrixXi F(triangulation.number_of_faces(),3);
|
||||
int f_row = 0;
|
||||
for(Delaunay::Finite_faces_iterator fit =
|
||||
triangulation.finite_faces_begin();
|
||||
fit != triangulation.finite_faces_end(); ++fit) {
|
||||
Delaunay::Face_handle face = fit;
|
||||
F.row(f_row) = Eigen::RowVector3i((int)face->vertex(0)->info(),
|
||||
(int)face->vertex(1)->info(),
|
||||
(int)face->vertex(2)->info());
|
||||
f_row++;
|
||||
}
|
||||
|
||||
//Here we calculate the voronoi area of the point
|
||||
scalarA area_accumulator = 0;
|
||||
for(int f = 0; f < F.rows(); f++){
|
||||
int X = -1;
|
||||
for(int face_iter = 0; face_iter < 3; face_iter++){
|
||||
if(F(f,face_iter) == 0){
|
||||
X = face_iter;
|
||||
}
|
||||
}
|
||||
if(X >= 0){
|
||||
//Triangle XYZ with X being the point we want the area of
|
||||
int Y = (X+1)%3;
|
||||
int Z = (X+2)%3;
|
||||
scalarA x = (plane.row(F(f,Y))-plane.row(F(f,Z))).norm();
|
||||
scalarA y = (plane.row(F(f,X))-plane.row(F(f,Z))).norm();
|
||||
scalarA z = (plane.row(F(f,Y))-plane.row(F(f,X))).norm();
|
||||
scalarA cosX = (z*z + y*y - x*x)/(2*y*z);
|
||||
scalarA cosY = (z*z + x*x - y*y)/(2*x*z);
|
||||
scalarA cosZ = (x*x + y*y - z*z)/(2*y*x);
|
||||
Eigen::Matrix<scalarA,1,3> barycentric;
|
||||
barycentric << x*cosX, y*cosY, z*cosZ;
|
||||
barycentric /= (barycentric(0)+barycentric(1)+barycentric(2));
|
||||
|
||||
//TODO: to make numerically stable, reorder so that x≥y≥z:
|
||||
scalarA full_area = 0.25*std::sqrt(
|
||||
(x+(y+z))*(z-(x-y))*(z+(x-y))*(x+(y-z)));
|
||||
Eigen::Matrix<scalarA,1,3> partial_area =
|
||||
barycentric * full_area;
|
||||
if(cosX < 0){
|
||||
area_accumulator += 0.5*full_area;
|
||||
} else if (cosY < 0 || cosZ < 0){
|
||||
area_accumulator += 0.25*full_area;
|
||||
} else {
|
||||
area_accumulator += (partial_area(1) + partial_area(2))/2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(std::isfinite(area_accumulator)){
|
||||
A(i) = area_accumulator;
|
||||
} else {
|
||||
A(i) = 0;
|
||||
}
|
||||
}
|
||||
},1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
78
src/igl/copyleft/cgal/point_areas.h
Normal file
78
src/igl/copyleft/cgal/point_areas.h
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2018 Gavin Barill <gavinpcb@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_POINT_AREAS_H
|
||||
#define IGL_POINT_AREAS_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Given a 3D set of points P, each with a list of k-nearest-neighbours,
|
||||
// estimate the geodesic voronoi area associated with each point.
|
||||
//
|
||||
// The k nearest neighbours may be known from running igl::knn_octree on
|
||||
// the output data from igl::octree. We reccomend using a k value
|
||||
// between 15 and 20 inclusive for accurate area estimation.
|
||||
//
|
||||
// N is used filter the neighbours, to ensure area estimation only occurs
|
||||
// using neighbors that are on the same side of the surface (ie for thin
|
||||
// sheets), as well as to solve the orientation ambiguity of the tangent
|
||||
// plane normal.
|
||||
//
|
||||
// Note: This function *should* be implemented by pre-filtering I, rather
|
||||
// than filtering in this function using N. In this case, the function
|
||||
// would only take P and I as input.
|
||||
//
|
||||
// Inputs:
|
||||
// P #P by 3 list of point locations
|
||||
// I #P by k list of k-nearest-neighbor indices into P
|
||||
// N #P by 3 list of point normals
|
||||
// Outputs:
|
||||
// A #P list of estimated areas
|
||||
template <typename DerivedP, typename DerivedI, typename DerivedN,
|
||||
typename DerivedA>
|
||||
IGL_INLINE void point_areas(
|
||||
const Eigen::MatrixBase<DerivedP>& P,
|
||||
const Eigen::MatrixBase<DerivedI>& I,
|
||||
const Eigen::MatrixBase<DerivedN>& N,
|
||||
Eigen::PlainObjectBase<DerivedA> & A);
|
||||
|
||||
// This version can be used to output the tangent plane normal at each
|
||||
// point. Since we area already fitting a plane to each point's neighbour
|
||||
// set, the tangent plane normals come "for free"
|
||||
//
|
||||
// Inputs:
|
||||
// P #P by 3 list of point locations
|
||||
// I #P by k list of k-nearest-neighbor indices into P
|
||||
// N #P by 3 list of point normals
|
||||
// Outputs:
|
||||
// A #P list of estimated areas
|
||||
// T #P by 3 list of tangent plane normals for each point
|
||||
template <typename DerivedP, typename DerivedI, typename DerivedN,
|
||||
typename DerivedA, typename DerivedT>
|
||||
IGL_INLINE void point_areas(
|
||||
const Eigen::MatrixBase<DerivedP>& P,
|
||||
const Eigen::MatrixBase<DerivedI>& I,
|
||||
const Eigen::MatrixBase<DerivedN>& N,
|
||||
Eigen::PlainObjectBase<DerivedA> & A,
|
||||
Eigen::PlainObjectBase<DerivedT> & T);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "point_areas.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
138
src/igl/copyleft/cgal/point_mesh_squared_distance.cpp
Normal file
138
src/igl/copyleft/cgal/point_mesh_squared_distance.cpp
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
// 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 "point_mesh_squared_distance.h"
|
||||
#include "mesh_to_cgal_triangle_list.h"
|
||||
#include "assign_scalar.h"
|
||||
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedP,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedsqrD,
|
||||
typename DerivedI,
|
||||
typename DerivedC>
|
||||
IGL_INLINE void igl::copyleft::cgal::point_mesh_squared_distance(
|
||||
const Eigen::PlainObjectBase<DerivedP> & P,
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
|
||||
Eigen::PlainObjectBase<DerivedI> & I,
|
||||
Eigen::PlainObjectBase<DerivedC> & C)
|
||||
{
|
||||
using namespace std;
|
||||
typedef CGAL::Triangle_3<Kernel> Triangle_3;
|
||||
typedef typename std::vector<Triangle_3>::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;
|
||||
Tree tree;
|
||||
vector<Triangle_3> T;
|
||||
point_mesh_squared_distance_precompute(V,F,tree,T);
|
||||
return point_mesh_squared_distance(P,tree,T,sqrD,I,C);
|
||||
}
|
||||
|
||||
template <typename Kernel, typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE void igl::copyleft::cgal::point_mesh_squared_distance_precompute(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
CGAL::AABB_tree<
|
||||
CGAL::AABB_traits<Kernel,
|
||||
CGAL::AABB_triangle_primitive<Kernel,
|
||||
typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
|
||||
>
|
||||
>
|
||||
> & tree,
|
||||
std::vector<CGAL::Triangle_3<Kernel> > & T)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
typedef CGAL::Triangle_3<Kernel> Triangle_3;
|
||||
typedef CGAL::Point_3<Kernel> Point_3;
|
||||
typedef typename std::vector<Triangle_3>::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;
|
||||
|
||||
// Must be 3D
|
||||
assert(V.cols() == 3);
|
||||
// Must be triangles
|
||||
assert(F.cols() == 3);
|
||||
|
||||
// WTF ALERT!!!!
|
||||
//
|
||||
// There's a bug in clang probably or at least in cgal. Without calling this
|
||||
// line (I guess invoking some compilation from <vector>), clang will vomit
|
||||
// errors inside CGAL.
|
||||
//
|
||||
// http://stackoverflow.com/questions/27748442/is-clangs-c11-support-reliable
|
||||
T.reserve(0);
|
||||
|
||||
// Make list of cgal triangles
|
||||
mesh_to_cgal_triangle_list(V,F,T);
|
||||
tree.clear();
|
||||
tree.insert(T.begin(),T.end());
|
||||
tree.accelerate_distance_queries();
|
||||
// accelerate_distance_queries doesn't seem actually to do _all_ of the
|
||||
// precomputation. the tree (despite being const) will still do more
|
||||
// precomputation and reorganizing on the first call of `closest_point` or
|
||||
// `closest_point_and_primitive`. Therefore, call it once here.
|
||||
tree.closest_point_and_primitive(Point_3(0,0,0));
|
||||
}
|
||||
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedP,
|
||||
typename DerivedsqrD,
|
||||
typename DerivedI,
|
||||
typename DerivedC>
|
||||
IGL_INLINE void igl::copyleft::cgal::point_mesh_squared_distance(
|
||||
const Eigen::PlainObjectBase<DerivedP> & P,
|
||||
const CGAL::AABB_tree<
|
||||
CGAL::AABB_traits<Kernel,
|
||||
CGAL::AABB_triangle_primitive<Kernel,
|
||||
typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
|
||||
>
|
||||
>
|
||||
> & tree,
|
||||
const std::vector<CGAL::Triangle_3<Kernel> > & T,
|
||||
Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
|
||||
Eigen::PlainObjectBase<DerivedI> & I,
|
||||
Eigen::PlainObjectBase<DerivedC> & C)
|
||||
{
|
||||
typedef CGAL::Triangle_3<Kernel> Triangle_3;
|
||||
typedef typename std::vector<Triangle_3>::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;
|
||||
typedef typename Tree::Point_and_primitive_id Point_and_primitive_id;
|
||||
typedef CGAL::Point_3<Kernel> Point_3;
|
||||
assert(P.cols() == 3);
|
||||
const int n = P.rows();
|
||||
sqrD.resize(n,1);
|
||||
I.resize(n,1);
|
||||
C.resize(n,P.cols());
|
||||
for(int p = 0;p < n;p++)
|
||||
{
|
||||
Point_3 query(P(p,0),P(p,1),P(p,2));
|
||||
// Find closest point and primitive id
|
||||
Point_and_primitive_id pp = tree.closest_point_and_primitive(query);
|
||||
Point_3 closest_point = pp.first;
|
||||
assign_scalar(closest_point[0],C(p,0));
|
||||
assign_scalar(closest_point[1],C(p,1));
|
||||
assign_scalar(closest_point[2],C(p,2));
|
||||
assign_scalar((closest_point-query).squared_length(),sqrD(p));
|
||||
I(p) = pp.second - T.begin();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::copyleft::cgal::point_mesh_squared_distance<CGAL::Epeck, 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::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -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> > const&, Eigen::PlainObjectBase<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<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::point_mesh_squared_distance<CGAL::Epeck, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > 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<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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> >&);
|
||||
#endif
|
||||
104
src/igl/copyleft/cgal/point_mesh_squared_distance.h
Normal file
104
src/igl/copyleft/cgal/point_mesh_squared_distance.h
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
// 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_POINT_MESH_SQUARED_DISTANCE_H
|
||||
#define IGL_COPYLEFT_CGAL_POINT_MESH_SQUARED_DISTANCE_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
#include "CGAL_includes.hpp"
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Compute distances from a set of points P to a triangle mesh (V,F)
|
||||
//
|
||||
// Templates:
|
||||
// Kernal CGAL computation and construction kernel (e.g.
|
||||
// CGAL::Simple_cartesian<double>)
|
||||
// Inputs:
|
||||
// P #P by 3 list of query point positions
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices
|
||||
// Outputs:
|
||||
// sqrD #P list of smallest squared distances
|
||||
// I #P list of facet indices corresponding to smallest distances
|
||||
// C #P by 3 list of closest points
|
||||
//
|
||||
// Known bugs: This only computes distances to triangles. So unreferenced
|
||||
// vertices and degenerate triangles (segments) are ignored.
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedP,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedsqrD,
|
||||
typename DerivedI,
|
||||
typename DerivedC>
|
||||
IGL_INLINE void point_mesh_squared_distance(
|
||||
const Eigen::PlainObjectBase<DerivedP> & P,
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
|
||||
Eigen::PlainObjectBase<DerivedI> & I,
|
||||
Eigen::PlainObjectBase<DerivedC> & C);
|
||||
// Probably can do this in a way that we don't pass around `tree` and `T`
|
||||
//
|
||||
// Outputs:
|
||||
// tree CGAL's AABB tree
|
||||
// T list of CGAL triangles in order of F (for determining which was found
|
||||
// in computation)
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF
|
||||
>
|
||||
IGL_INLINE void point_mesh_squared_distance_precompute(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
CGAL::AABB_tree<
|
||||
CGAL::AABB_traits<Kernel,
|
||||
CGAL::AABB_triangle_primitive<Kernel,
|
||||
typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
|
||||
>
|
||||
>
|
||||
> & tree,
|
||||
std::vector<CGAL::Triangle_3<Kernel> > & T);
|
||||
// Inputs:
|
||||
// see above
|
||||
// Outputs:
|
||||
// see above
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedP,
|
||||
typename DerivedsqrD,
|
||||
typename DerivedI,
|
||||
typename DerivedC>
|
||||
IGL_INLINE void point_mesh_squared_distance(
|
||||
const Eigen::PlainObjectBase<DerivedP> & P,
|
||||
const CGAL::AABB_tree<
|
||||
CGAL::AABB_traits<Kernel,
|
||||
CGAL::AABB_triangle_primitive<Kernel,
|
||||
typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
|
||||
>
|
||||
>
|
||||
> & tree,
|
||||
const std::vector<CGAL::Triangle_3<Kernel> > & T,
|
||||
Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
|
||||
Eigen::PlainObjectBase<DerivedI> & I,
|
||||
Eigen::PlainObjectBase<DerivedC> & C);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "point_mesh_squared_distance.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
41
src/igl/copyleft/cgal/point_segment_squared_distance.cpp
Normal file
41
src/igl/copyleft/cgal/point_segment_squared_distance.cpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// 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 "point_segment_squared_distance.h"
|
||||
|
||||
template < typename Kernel>
|
||||
IGL_INLINE void igl::copyleft::cgal::point_segment_squared_distance(
|
||||
const CGAL::Point_3<Kernel> & P1,
|
||||
const CGAL::Segment_3<Kernel> & S2,
|
||||
CGAL::Point_3<Kernel> & P2,
|
||||
typename Kernel::FT & d)
|
||||
{
|
||||
if(S2.is_degenerate())
|
||||
{
|
||||
P2 = S2.source();
|
||||
d = (P1-P2).squared_length();
|
||||
return;
|
||||
}
|
||||
// http://stackoverflow.com/a/1501725/148668
|
||||
const auto sqr_len = S2.squared_length();
|
||||
assert(sqr_len != 0);
|
||||
const auto & V = S2.source();
|
||||
const auto & W = S2.target();
|
||||
const auto t = (P1-V).dot(W-V)/sqr_len;
|
||||
if(t<0)
|
||||
{
|
||||
P2 = V;
|
||||
}else if(t>1)
|
||||
{
|
||||
P2 = W;
|
||||
}else
|
||||
{
|
||||
P2 = V + t*(W-V);
|
||||
}
|
||||
d = (P1-P2).squared_length();
|
||||
}
|
||||
|
||||
44
src/igl/copyleft/cgal/point_segment_squared_distance.h
Normal file
44
src/igl/copyleft/cgal/point_segment_squared_distance.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// 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_POINT_SEGMENT_SQUARED_DISTANCE_H
|
||||
#define IGL_COPYLEFT_CGAL_POINT_SEGMENT_SQUARED_DISTANCE_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <CGAL/Segment_3.h>
|
||||
#include <CGAL/Point_3.h>
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Given a point P1 and segment S2 find the points on each of closest
|
||||
// approach and the squared distance thereof.
|
||||
//
|
||||
// Inputs:
|
||||
// P1 point
|
||||
// S2 segment
|
||||
// Outputs:
|
||||
// P2 point on S2 closest to P1
|
||||
// d distance betwee P1 and S2
|
||||
template < typename Kernel>
|
||||
IGL_INLINE void point_segment_squared_distance(
|
||||
const CGAL::Point_3<Kernel> & P1,
|
||||
const CGAL::Segment_3<Kernel> & S2,
|
||||
CGAL::Point_3<Kernel> & P2,
|
||||
typename Kernel::FT & d
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "point_segment_squared_distance.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
// 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 "point_solid_signed_squared_distance.h"
|
||||
#include "points_inside_component.h"
|
||||
#include "point_mesh_squared_distance.h"
|
||||
#include "../../list_to_matrix.h"
|
||||
#include "../../slice_mask.h"
|
||||
#include <vector>
|
||||
#include <Eigen/Core>
|
||||
|
||||
template <
|
||||
typename DerivedQ,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedD>
|
||||
IGL_INLINE void igl::copyleft::cgal::point_solid_signed_squared_distance(
|
||||
const Eigen::PlainObjectBase<DerivedQ> & Q,
|
||||
const Eigen::PlainObjectBase<DerivedVB> & VB,
|
||||
const Eigen::PlainObjectBase<DerivedFB> & FB,
|
||||
Eigen::PlainObjectBase<DerivedD> & D)
|
||||
{
|
||||
// compute unsigned distances
|
||||
Eigen::VectorXi I;
|
||||
DerivedVB C;
|
||||
point_mesh_squared_distance<CGAL::Epeck>(Q,VB,FB,D,I,C);
|
||||
// Collect queries that have non-zero distance
|
||||
Eigen::Array<bool,Eigen::Dynamic,1> NZ = D.array()!=0;
|
||||
// Compute sign for non-zero distance queries
|
||||
DerivedQ QNZ;
|
||||
slice_mask(Q,NZ,1,QNZ);
|
||||
Eigen::Array<bool,Eigen::Dynamic,1> DNZ;
|
||||
igl::copyleft::cgal::points_inside_component(VB,FB,QNZ,DNZ);
|
||||
// Apply sign to distances
|
||||
DerivedD S = DerivedD::Zero(Q.rows(),1);
|
||||
{
|
||||
int k = 0;
|
||||
for(int q = 0;q<Q.rows();q++)
|
||||
{
|
||||
if(NZ(q))
|
||||
{
|
||||
D(q) *= DNZ(k++) ? -1. : 1.;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::point_solid_signed_squared_distance<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > 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<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
48
src/igl/copyleft/cgal/point_solid_signed_squared_distance.h
Normal file
48
src/igl/copyleft/cgal/point_solid_signed_squared_distance.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
// 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_POINT_SOLID_SIGNED_SQUARED_DISTANCE_H
|
||||
#define IGL_COPYLEFT_CGAL_POINT_SOLID_SIGNED_SQUARED_DISTANCE_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// POINT_SOLID_SIGNED_SQUARED_DISTANCE Given a set of points (Q) and the
|
||||
// boundary mesh (VB,FB) of a solid (as defined in [Zhou et al. 2016],
|
||||
// determine the signed squared distance for each point q in Q so that d(q,B) is
|
||||
// negative if inside and positive if outside.
|
||||
//
|
||||
// Inputs:
|
||||
// Q #Q by 3 list of query point positions
|
||||
// VB #VB by 3 list of mesh vertex positions of B
|
||||
// FB #FB by 3 list of mesh triangle indices into VB
|
||||
// Outputs:
|
||||
// D
|
||||
template <
|
||||
typename DerivedQ,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedD>
|
||||
IGL_INLINE void point_solid_signed_squared_distance(
|
||||
const Eigen::PlainObjectBase<DerivedQ> & Q,
|
||||
const Eigen::PlainObjectBase<DerivedVB> & VB,
|
||||
const Eigen::PlainObjectBase<DerivedFB> & FB,
|
||||
Eigen::PlainObjectBase<DerivedD> & D);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "point_solid_signed_squared_distance.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
47
src/igl/copyleft/cgal/point_triangle_squared_distance.cpp
Normal file
47
src/igl/copyleft/cgal/point_triangle_squared_distance.cpp
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// 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 "point_triangle_squared_distance.h"
|
||||
#include <CGAL/Segment_3.h>
|
||||
template < typename Kernel>
|
||||
IGL_INLINE void point_triangle_squared_distance(
|
||||
const CGAL::Point_3<Kernel> & P1,
|
||||
const CGAL::Triangle_3<Kernel> & T2,
|
||||
CGAL::Point_3<Kernel> & P2,
|
||||
typename Kernel::FT & d)
|
||||
{
|
||||
assert(!T2.is_degenerate());
|
||||
if(T2.has_on(P1))
|
||||
{
|
||||
P2 = P1;
|
||||
d = 0;
|
||||
return;
|
||||
}
|
||||
const auto proj_1 = T2.supporting_plane().projection(P2);
|
||||
if(T2.has_on(proj_1))
|
||||
{
|
||||
P2 = proj_1;
|
||||
d = (proj_1-P1).squared_length();
|
||||
return;
|
||||
}
|
||||
// closest point must be on the boundary
|
||||
bool first = true;
|
||||
// loop over edges
|
||||
for(int i=0;i<3;i++)
|
||||
{
|
||||
CGAL::Point_3<Kernel> P2i;
|
||||
typename Kernel::FT di;
|
||||
const CGAL::Segment_3<Kernel> si( T2.vertex(i+1), T2.vertex(i+2));
|
||||
point_segment_squared_distance(P1,si,P2i,di);
|
||||
if(first || di < d)
|
||||
{
|
||||
first = false;
|
||||
d = di;
|
||||
P2 = P2i;
|
||||
}
|
||||
}
|
||||
}
|
||||
45
src/igl/copyleft/cgal/point_triangle_squared_distance.h
Normal file
45
src/igl/copyleft/cgal/point_triangle_squared_distance.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
// 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_POINT_TRIANGLE_SQUARED_DISTANCE_H
|
||||
#define IGL_COPYLEFT_CGAL_POINT_TRIANGLE_SQUARED_DISTANCE_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <CGAL/Triangle_3.h>
|
||||
#include <CGAL/Point_3.h>
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Given a point P1 and triangle T2 find the points on each of closest
|
||||
// approach and the squared distance thereof.
|
||||
//
|
||||
// Inputs:
|
||||
// P1 point
|
||||
// T2 triangle
|
||||
// Outputs:
|
||||
// P2 point on T2 closest to P1
|
||||
// d distance betwee P1 and T2
|
||||
template < typename Kernel>
|
||||
IGL_INLINE void point_triangle_squared_distance(
|
||||
const CGAL::Point_3<Kernel> & P1,
|
||||
const CGAL::Triangle_3<Kernel> & T2,
|
||||
CGAL::Point_3<Kernel> & P2,
|
||||
typename Kernel::FT & d
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "point_triangle_squared_distance.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
350
src/igl/copyleft/cgal/points_inside_component.cpp
Normal file
350
src/igl/copyleft/cgal/points_inside_component.cpp
Normal file
|
|
@ -0,0 +1,350 @@
|
|||
// 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 "points_inside_component.h"
|
||||
#include "../../LinSpaced.h"
|
||||
#include "order_facets_around_edge.h"
|
||||
#include "assign_scalar.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>
|
||||
|
||||
|
||||
namespace igl {
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal {
|
||||
namespace points_inside_component_helper {
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
|
||||
typedef Kernel::Ray_3 Ray_3;
|
||||
typedef Kernel::Point_3 Point_3;
|
||||
typedef Kernel::Vector_3 Vector_3;
|
||||
typedef Kernel::Triangle_3 Triangle;
|
||||
typedef Kernel::Plane_3 Plane_3;
|
||||
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;
|
||||
|
||||
template<typename DerivedF, typename DerivedI>
|
||||
void extract_adj_faces(
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I,
|
||||
const size_t s, const size_t d,
|
||||
std::vector<int>& adj_faces) {
|
||||
const size_t num_faces = I.rows();
|
||||
for (size_t i=0; i<num_faces; i++) {
|
||||
Eigen::Vector3i f = F.row(I(i, 0));
|
||||
if (((size_t)f[0] == s && (size_t)f[1] == d) ||
|
||||
((size_t)f[1] == s && (size_t)f[2] == d) ||
|
||||
((size_t)f[2] == s && (size_t)f[0] == d)) {
|
||||
adj_faces.push_back((I(i, 0)+1) * -1);
|
||||
continue;
|
||||
}
|
||||
if (((size_t)f[0] == d && (size_t)f[1] == s) ||
|
||||
((size_t)f[1] == d && (size_t)f[2] == s) ||
|
||||
((size_t)f[2] == d && (size_t)f[0] == s)) {
|
||||
adj_faces.push_back(I(i, 0)+1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename DerivedF, typename DerivedI>
|
||||
void extract_adj_vertices(
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I,
|
||||
const size_t v, std::vector<int>& adj_vertices) {
|
||||
std::set<size_t> unique_adj_vertices;
|
||||
const size_t num_faces = I.rows();
|
||||
for (size_t i=0; i<num_faces; i++) {
|
||||
Eigen::Vector3i f = F.row(I(i, 0));
|
||||
if ((size_t)f[0] == v) {
|
||||
unique_adj_vertices.insert(f[1]);
|
||||
unique_adj_vertices.insert(f[2]);
|
||||
} else if ((size_t)f[1] == v) {
|
||||
unique_adj_vertices.insert(f[0]);
|
||||
unique_adj_vertices.insert(f[2]);
|
||||
} else if ((size_t)f[2] == v) {
|
||||
unique_adj_vertices.insert(f[0]);
|
||||
unique_adj_vertices.insert(f[1]);
|
||||
}
|
||||
}
|
||||
adj_vertices.resize(unique_adj_vertices.size());
|
||||
std::copy(unique_adj_vertices.begin(),
|
||||
unique_adj_vertices.end(),
|
||||
adj_vertices.begin());
|
||||
}
|
||||
|
||||
template<typename DerivedV, typename DerivedF, typename DerivedI>
|
||||
bool determine_point_edge_orientation(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I,
|
||||
const Point_3& query, size_t s, size_t d) {
|
||||
// Algorithm:
|
||||
//
|
||||
// Order the adj faces around the edge (s,d) clockwise using
|
||||
// query point as pivot. (i.e. The first face of the ordering
|
||||
// is directly after the pivot point, and the last face is
|
||||
// directly before the pivot.)
|
||||
//
|
||||
// The point is outside if the first and last faces of the
|
||||
// ordering forms a convex angle. This check can be done
|
||||
// without any construction by looking at the orientation of the
|
||||
// faces. The angle is convex iff the first face contains (s,d)
|
||||
// as an edge and the last face contains (d,s) as an edge.
|
||||
//
|
||||
// The point is inside if the first and last faces of the
|
||||
// ordering forms a concave angle. That is the first face
|
||||
// contains (d,s) as an edge and the last face contains (s,d) as
|
||||
// an edge.
|
||||
//
|
||||
// In the special case of duplicated faces. I.e. multiple faces
|
||||
// sharing the same 3 corners, but not necessarily the same
|
||||
// orientation. The ordering will always rank faces containing
|
||||
// edge (s,d) before faces containing edge (d,s).
|
||||
//
|
||||
// Therefore, if there are any duplicates of the first faces,
|
||||
// the ordering will always choose the one with edge (s,d) if
|
||||
// possible. The same for the last face.
|
||||
//
|
||||
// In the very degenerated case where the first and last face
|
||||
// are duplicates, but with different orientations, it is
|
||||
// equally valid to think the angle formed by them is either 0
|
||||
// or 360 degrees. By default, 0 degree is used, and thus the
|
||||
// query point is outside.
|
||||
|
||||
std::vector<int> adj_faces;
|
||||
extract_adj_faces(F, I, s, d, adj_faces);
|
||||
const size_t num_adj_faces = adj_faces.size();
|
||||
assert(num_adj_faces > 0);
|
||||
|
||||
DerivedV pivot_point(1, 3);
|
||||
igl::copyleft::cgal::assign_scalar(query.x(), pivot_point(0, 0));
|
||||
igl::copyleft::cgal::assign_scalar(query.y(), pivot_point(0, 1));
|
||||
igl::copyleft::cgal::assign_scalar(query.z(), pivot_point(0, 2));
|
||||
Eigen::VectorXi order;
|
||||
order_facets_around_edge(V, F, s, d,
|
||||
adj_faces, pivot_point, order);
|
||||
assert((size_t)order.size() == num_adj_faces);
|
||||
if (adj_faces[order[0]] > 0 &&
|
||||
adj_faces[order[num_adj_faces-1] < 0]) {
|
||||
return true;
|
||||
} else if (adj_faces[order[0]] < 0 &&
|
||||
adj_faces[order[num_adj_faces-1] > 0]) {
|
||||
return false;
|
||||
} else {
|
||||
throw "The input mesh does not represent a valid volume";
|
||||
}
|
||||
throw "The input mesh does not represent a valid volume";
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename DerivedV, typename DerivedF, typename DerivedI>
|
||||
bool determine_point_vertex_orientation(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I,
|
||||
const Point_3& query, size_t s) {
|
||||
std::vector<int> adj_vertices;
|
||||
extract_adj_vertices(F, I, s, adj_vertices);
|
||||
const size_t num_adj_vertices = adj_vertices.size();
|
||||
|
||||
std::vector<Point_3> adj_points;
|
||||
for (size_t i=0; i<num_adj_vertices; i++) {
|
||||
const size_t vi = adj_vertices[i];
|
||||
adj_points.emplace_back(V(vi,0), V(vi,1), V(vi,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);
|
||||
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();
|
||||
Point_3 p(V(s,0), V(s,1), V(s,2));
|
||||
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(p, adj_points[i], adj_points[j]);
|
||||
if (separator.is_degenerate()) {
|
||||
throw "Input mesh contains degenerated faces";
|
||||
}
|
||||
if (is_on_exterior(separator)) {
|
||||
d = vi;
|
||||
assert(!CGAL::collinear(p, adj_points[i], query));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (d < (size_t)V.rows()) break;
|
||||
}
|
||||
if (d > (size_t)V.rows()) {
|
||||
// All adj faces are coplanar, use the first edge.
|
||||
d = adj_vertices[0];
|
||||
}
|
||||
return determine_point_edge_orientation(V, F, I, query, s, d);
|
||||
}
|
||||
|
||||
template<typename DerivedV, typename DerivedF, typename DerivedI>
|
||||
bool determine_point_face_orientation(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I,
|
||||
const Point_3& query, size_t fid) {
|
||||
// Algorithm: A point is on the inside of a face if the
|
||||
// tetrahedron formed by them is negatively oriented.
|
||||
|
||||
Eigen::Vector3i f = F.row(I(fid, 0));
|
||||
const Point_3 v0(V(f[0], 0), V(f[0], 1), V(f[0], 2));
|
||||
const Point_3 v1(V(f[1], 0), V(f[1], 1), V(f[1], 2));
|
||||
const Point_3 v2(V(f[2], 0), V(f[2], 1), V(f[2], 2));
|
||||
auto result = CGAL::orientation(v0, v1, v2, query);
|
||||
if (result == CGAL::COPLANAR) {
|
||||
throw "Cannot determine inside/outside because query point lies exactly on the input surface.";
|
||||
}
|
||||
return result == CGAL::NEGATIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename DerivedV, typename DerivedF, typename DerivedI,
|
||||
typename DerivedP, typename DerivedB>
|
||||
IGL_INLINE void igl::copyleft::cgal::points_inside_component(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
Eigen::PlainObjectBase<DerivedB>& inside) {
|
||||
using namespace igl::copyleft::cgal::points_inside_component_helper;
|
||||
if (F.rows() <= 0 || I.rows() <= 0) {
|
||||
throw "Inside check cannot be done on empty facet component.";
|
||||
}
|
||||
|
||||
const size_t num_faces = I.rows();
|
||||
std::vector<Triangle> triangles;
|
||||
for (size_t i=0; i<num_faces; i++) {
|
||||
const Eigen::Vector3i f = F.row(I(i, 0));
|
||||
triangles.emplace_back(
|
||||
Point_3(V(f[0], 0), V(f[0], 1), V(f[0], 2)),
|
||||
Point_3(V(f[1], 0), V(f[1], 1), V(f[1], 2)),
|
||||
Point_3(V(f[2], 0), V(f[2], 1), V(f[2], 2)));
|
||||
if (triangles.back().is_degenerate()) {
|
||||
throw "Input facet components contains degenerated triangles";
|
||||
}
|
||||
}
|
||||
Tree tree(triangles.begin(), triangles.end());
|
||||
tree.accelerate_distance_queries();
|
||||
|
||||
enum ElementType { VERTEX, EDGE, FACE };
|
||||
auto determine_element_type = [&](
|
||||
size_t fid, const Point_3& p, size_t& element_index) -> ElementType{
|
||||
const Eigen::Vector3i f = F.row(I(fid, 0));
|
||||
const Point_3 p0(V(f[0], 0), V(f[0], 1), V(f[0], 2));
|
||||
const Point_3 p1(V(f[1], 0), V(f[1], 1), V(f[1], 2));
|
||||
const Point_3 p2(V(f[2], 0), V(f[2], 1), V(f[2], 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;
|
||||
};
|
||||
|
||||
const size_t num_queries = P.rows();
|
||||
inside.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);
|
||||
auto closest_point = projection.first;
|
||||
size_t fid = projection.second - triangles.begin();
|
||||
|
||||
size_t element_index;
|
||||
switch (determine_element_type(fid, closest_point, element_index)) {
|
||||
case VERTEX:
|
||||
{
|
||||
const size_t s = F(I(fid, 0), element_index);
|
||||
inside(i,0) = determine_point_vertex_orientation(
|
||||
V, F, I, query, s);
|
||||
}
|
||||
break;
|
||||
case EDGE:
|
||||
{
|
||||
const size_t s = F(I(fid, 0), (element_index+1)%3);
|
||||
const size_t d = F(I(fid, 0), (element_index+2)%3);
|
||||
inside(i,0) = determine_point_edge_orientation(
|
||||
V, F, I, query, s, d);
|
||||
}
|
||||
break;
|
||||
case FACE:
|
||||
inside(i,0) = determine_point_face_orientation(V, F, I, query, fid);
|
||||
break;
|
||||
default:
|
||||
throw "Unknown closest element type!";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename DerivedV, typename DerivedF, typename DerivedP,
|
||||
typename DerivedB>
|
||||
IGL_INLINE void igl::copyleft::cgal::points_inside_component(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
Eigen::PlainObjectBase<DerivedB>& inside) {
|
||||
Eigen::VectorXi I = igl::LinSpaced<Eigen::VectorXi>(F.rows(), 0, F.rows()-1);
|
||||
igl::copyleft::cgal::points_inside_component(V, F, I, P, inside);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::points_inside_component<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Array<bool, -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<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Array<bool, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::points_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::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< 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> >&);
|
||||
template void igl::copyleft::cgal::points_inside_component< 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::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> >&);
|
||||
template void igl::copyleft::cgal::points_inside_component<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::points_inside_component<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::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::points_inside_component<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::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> >&);
|
||||
template void igl::copyleft::cgal::points_inside_component<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
71
src/igl/copyleft/cgal/points_inside_component.h
Normal file
71
src/igl/copyleft/cgal/points_inside_component.h
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
// 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_POINTS_INSIDE_COMPONENTS
|
||||
#define IGL_COPYLEFT_CGAL_POINTS_INSIDE_COMPONENTS
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal {
|
||||
|
||||
// Determine if queries points P are inside of connected facet component
|
||||
// (V, F, I), where I indicates a subset of facets that forms the
|
||||
// component.
|
||||
//
|
||||
// Precondition:
|
||||
// The input mesh must be a closed, self-intersection free,
|
||||
// non-degenerated surface. Queries points must be either inside or
|
||||
// outside of the mesh (i.e. not on the surface of the mesh).
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 array of vertex positions.
|
||||
// F #F by 3 array of triangles.
|
||||
// I #I list of triangle indices to consider.
|
||||
// P #P by 3 array of query points.
|
||||
//
|
||||
// Outputs:
|
||||
// inside #P list of booleans that is true iff the corresponding
|
||||
// query point is inside of the mesh.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename DerivedP,
|
||||
typename DerivedB>
|
||||
IGL_INLINE void points_inside_component(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
Eigen::PlainObjectBase<DerivedB>& inside);
|
||||
|
||||
// Determine if query points P is inside of the mesh (V, F).
|
||||
// See above for precondition and I/O specs.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename DerivedB>
|
||||
IGL_INLINE void points_inside_component(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
Eigen::PlainObjectBase<DerivedB>& inside);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
#include "points_inside_component.cpp"
|
||||
#endif
|
||||
#endif
|
||||
69
src/igl/copyleft/cgal/polyhedron_to_mesh.cpp
Normal file
69
src/igl/copyleft/cgal/polyhedron_to_mesh.cpp
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
// 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 "polyhedron_to_mesh.h"
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
|
||||
template <
|
||||
typename Polyhedron,
|
||||
typename DerivedV,
|
||||
typename DerivedF>
|
||||
IGL_INLINE void igl::copyleft::cgal::polyhedron_to_mesh(
|
||||
const Polyhedron & poly,
|
||||
Eigen::PlainObjectBase<DerivedV> & V,
|
||||
Eigen::PlainObjectBase<DerivedF> & F)
|
||||
{
|
||||
using namespace std;
|
||||
V.resize(poly.size_of_vertices(),3);
|
||||
F.resize(poly.size_of_facets(),3);
|
||||
typedef typename Polyhedron::Vertex_const_iterator Vertex_iterator;
|
||||
std::map<Vertex_iterator,size_t> vertex_to_index;
|
||||
{
|
||||
size_t v = 0;
|
||||
for(
|
||||
typename Polyhedron::Vertex_const_iterator p = poly.vertices_begin();
|
||||
p != poly.vertices_end();
|
||||
p++)
|
||||
{
|
||||
V(v,0) = p->point().x();
|
||||
V(v,1) = p->point().y();
|
||||
V(v,2) = p->point().z();
|
||||
vertex_to_index[p] = v;
|
||||
v++;
|
||||
}
|
||||
}
|
||||
{
|
||||
size_t f = 0;
|
||||
for(
|
||||
typename Polyhedron::Facet_const_iterator facet = poly.facets_begin();
|
||||
facet != poly.facets_end();
|
||||
++facet)
|
||||
{
|
||||
typename Polyhedron::Halfedge_around_facet_const_circulator he =
|
||||
facet->facet_begin();
|
||||
// Facets in polyhedral surfaces are at least triangles.
|
||||
assert(CGAL::circulator_size(he) == 3 && "Facets should be triangles");
|
||||
size_t c = 0;
|
||||
do {
|
||||
//// This is stooopidly slow
|
||||
// F(f,c) = std::distance(poly.vertices_begin(), he->vertex());
|
||||
F(f,c) = vertex_to_index[he->vertex()];
|
||||
c++;
|
||||
} while ( ++he != facet->facet_begin());
|
||||
f++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Polyhedron_items_with_id_3.h>
|
||||
template void igl::copyleft::cgal::polyhedron_to_mesh<CGAL::Polyhedron_3<CGAL::Epick, CGAL::Polyhedron_items_3, CGAL::HalfedgeDS_default, std::allocator<int> >, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(CGAL::Polyhedron_3<CGAL::Epick, CGAL::Polyhedron_items_3, CGAL::HalfedgeDS_default, std::allocator<int> > 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::polyhedron_to_mesh<CGAL::Polyhedron_3<CGAL::Simple_cartesian<double>,CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator<int> >, Eigen::Matrix<double, -1, -1, 0,-1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(CGAL::Polyhedron_3<CGAL::Simple_cartesian<double>,CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator<int> > const&,Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0,-1, -1> >&);
|
||||
#endif
|
||||
43
src/igl/copyleft/cgal/polyhedron_to_mesh.h
Normal file
43
src/igl/copyleft/cgal/polyhedron_to_mesh.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// 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_POLYHEDRON_TO_MESH_H
|
||||
#define IGL_COPYLEFT_CGAL_POLYHEDRON_TO_MESH_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Convert a CGAL Polyhedron to a mesh (V,F)
|
||||
//
|
||||
// Templates:
|
||||
// Polyhedron CGAL Polyhedron type (e.g. Polyhedron_3)
|
||||
// Inputs:
|
||||
// poly cgal polyhedron
|
||||
// Outputs:
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices
|
||||
template <
|
||||
typename Polyhedron,
|
||||
typename DerivedV,
|
||||
typename DerivedF>
|
||||
IGL_INLINE void polyhedron_to_mesh(
|
||||
const Polyhedron & poly,
|
||||
Eigen::PlainObjectBase<DerivedV> & V,
|
||||
Eigen::PlainObjectBase<DerivedF> & F);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "polyhedron_to_mesh.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
82
src/igl/copyleft/cgal/projected_cdt.cpp
Normal file
82
src/igl/copyleft/cgal/projected_cdt.cpp
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson
|
||||
//
|
||||
// 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 "projected_cdt.h"
|
||||
#include "insert_into_cdt.h"
|
||||
#include "assign_scalar.h"
|
||||
#include "../../list_to_matrix.h"
|
||||
template <typename Kernel, typename Index>
|
||||
IGL_INLINE void igl::copyleft::cgal::projected_cdt(
|
||||
const std::vector<CGAL::Object> & objects,
|
||||
const CGAL::Plane_3<Kernel> & P,
|
||||
std::vector<CGAL::Point_3<Kernel> >& vertices,
|
||||
std::vector<std::vector<Index> >& faces)
|
||||
{
|
||||
typedef CGAL::Triangulation_vertex_base_2<Kernel> TVB_2;
|
||||
typedef CGAL::Constrained_triangulation_face_base_2<Kernel> CTFB_2;
|
||||
typedef CGAL::Triangulation_data_structure_2<TVB_2,CTFB_2> TDS_2;
|
||||
typedef CGAL::Exact_intersections_tag Itag;
|
||||
typedef CGAL::Constrained_Delaunay_triangulation_2<Kernel,TDS_2,Itag> CDT_2;
|
||||
typedef CGAL::Constrained_triangulation_plus_2<CDT_2> CDT_plus_2;
|
||||
CDT_plus_2 cdt;
|
||||
for(const auto & obj : objects) insert_into_cdt(obj,P,cdt);
|
||||
// Read off vertices of the cdt, remembering index
|
||||
std::map<typename CDT_plus_2::Vertex_handle,Index> v2i;
|
||||
size_t count=0;
|
||||
for (
|
||||
auto itr = cdt.finite_vertices_begin();
|
||||
itr != cdt.finite_vertices_end();
|
||||
itr++)
|
||||
{
|
||||
vertices.push_back(P.to_3d(itr->point()));
|
||||
v2i[itr] = count;
|
||||
count++;
|
||||
}
|
||||
// Read off faces and store index triples
|
||||
for (
|
||||
auto itr = cdt.finite_faces_begin();
|
||||
itr != cdt.finite_faces_end();
|
||||
itr++)
|
||||
{
|
||||
faces.push_back(
|
||||
{ v2i[itr->vertex(0)], v2i[itr->vertex(1)], v2i[itr->vertex(2)] });
|
||||
}
|
||||
}
|
||||
|
||||
template < typename Kernel, typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE void igl::copyleft::cgal::projected_cdt(
|
||||
const std::vector<CGAL::Object> & objects,
|
||||
const CGAL::Plane_3<Kernel> & P,
|
||||
Eigen::PlainObjectBase<DerivedV> & V,
|
||||
Eigen::PlainObjectBase<DerivedF> & F)
|
||||
{
|
||||
std::vector<CGAL::Point_3<Kernel> > vertices;
|
||||
std::vector<std::vector<typename DerivedF::Scalar> > faces;
|
||||
projected_cdt(objects,P,vertices,faces);
|
||||
V.resize(vertices.size(),3);
|
||||
for(int v = 0;v<vertices.size();v++)
|
||||
{
|
||||
for(int d = 0;d<3;d++)
|
||||
{
|
||||
assign_scalar(vertices[v][d], V(v,d));
|
||||
}
|
||||
}
|
||||
list_to_matrix(faces,F);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::projected_cdt<CGAL::Epick, long>(std::vector<CGAL::Object, std::allocator<CGAL::Object> > const&, CGAL::Plane_3<CGAL::Epick> const&, std::vector<CGAL::Point_3<CGAL::Epick>, std::allocator<CGAL::Point_3<CGAL::Epick> > >&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::projected_cdt<CGAL::Epeck, long>(std::vector<CGAL::Object, std::allocator<CGAL::Object> > const&, CGAL::Plane_3<CGAL::Epeck> const&, std::vector<CGAL::Point_3<CGAL::Epeck>, std::allocator<CGAL::Point_3<CGAL::Epeck> > >&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&);
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#ifdef WIN32
|
||||
template void igl::copyleft::cgal::projected_cdt<class CGAL::Epeck, __int64>(class std::vector<class CGAL::Object, class std::allocator<class CGAL::Object>> const &, class CGAL::Plane_3<class CGAL::Epeck> const &, class std::vector<class CGAL::Point_3<class CGAL::Epeck>, class std::allocator<class CGAL::Point_3<class CGAL::Epeck>>> &, class std::vector<class std::vector<__int64, class std::allocator<__int64>>, class std::allocator<class std::vector<__int64, class std::allocator<__int64>>>> &);
|
||||
template void igl::copyleft::cgal::projected_cdt<class CGAL::Epick, __int64>(class std::vector<class CGAL::Object, class std::allocator<class CGAL::Object>> const &, class CGAL::Plane_3<class CGAL::Epick> const &, class std::vector<class CGAL::Point_3<class CGAL::Epick>, class std::allocator<class CGAL::Point_3<class CGAL::Epick>>> &, class std::vector<class std::vector<__int64, class std::allocator<__int64>>, class std::allocator<class std::vector<__int64, class std::allocator<__int64>>>> &);
|
||||
#endif
|
||||
#endif
|
||||
61
src/igl/copyleft/cgal/projected_cdt.h
Normal file
61
src/igl/copyleft/cgal/projected_cdt.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson
|
||||
//
|
||||
// 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_PROJECTED_CDT_H
|
||||
#define IGL_COPYLEFT_CGAL_PROJECTED_CDT_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <CGAL/Plane_3.h>
|
||||
#include <CGAL/Point_3.h>
|
||||
#include <CGAL/Object.h>
|
||||
#include <vector>
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Given a list of objects (e.g., resulting from intersecting a triangle
|
||||
// with many other triangles), construct a constrained Delaunay
|
||||
// triangulation on a given plane (P), by inersting constraints for each
|
||||
// object projected onto that plane.
|
||||
//
|
||||
// Inputs:
|
||||
// objects list of objects. This should lie on the given plane (P),
|
||||
// otherwise they are added to the cdt _after_ their non-trivial
|
||||
// projection
|
||||
// P plane upon which all objects lie and upon which the CDT is
|
||||
// conducted
|
||||
// Outputs:
|
||||
// vertices list of vertices of the CDT mesh _back on the 3D plane_
|
||||
// faces list of list of triangle indices into vertices
|
||||
//
|
||||
template <typename Kernel, typename Index>
|
||||
IGL_INLINE void projected_cdt(
|
||||
const std::vector<CGAL::Object> & objects,
|
||||
const CGAL::Plane_3<Kernel> & P,
|
||||
std::vector<CGAL::Point_3<Kernel> >& vertices,
|
||||
std::vector<std::vector<Index> >& faces);
|
||||
// Outputs:
|
||||
// V #V by 3 list of vertices of the CDT mesh _back on the 3D plane_,
|
||||
// **cast** from the number type of Kernel to the number type of
|
||||
// DerivedV
|
||||
// F #F by 3 list of triangle indices into V
|
||||
template < typename Kernel, typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE void projected_cdt(
|
||||
const std::vector<CGAL::Object> & objects,
|
||||
const CGAL::Plane_3<Kernel> & P,
|
||||
Eigen::PlainObjectBase<DerivedV> & V,
|
||||
Eigen::PlainObjectBase<DerivedF> & F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "projected_cdt.cpp"
|
||||
#endif
|
||||
#endif
|
||||
106
src/igl/copyleft/cgal/projected_delaunay.cpp
Normal file
106
src/igl/copyleft/cgal/projected_delaunay.cpp
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
// 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 "projected_delaunay.h"
|
||||
#include "../../REDRUM.h"
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
#if CGAL_VERSION_NR < 1040611000
|
||||
# warning "CGAL Version < 4.6.1 may result in crashes. Please upgrade CGAL"
|
||||
#endif
|
||||
|
||||
template <typename Kernel>
|
||||
IGL_INLINE void igl::copyleft::cgal::projected_delaunay(
|
||||
const CGAL::Triangle_3<Kernel> & A,
|
||||
const std::vector<CGAL::Object> & A_objects_3,
|
||||
CGAL::Constrained_triangulation_plus_2<
|
||||
CGAL::Constrained_Delaunay_triangulation_2<
|
||||
Kernel,
|
||||
CGAL::Triangulation_data_structure_2<
|
||||
CGAL::Triangulation_vertex_base_2<Kernel>,
|
||||
CGAL::Constrained_triangulation_face_base_2<Kernel> >,
|
||||
CGAL::Exact_intersections_tag> > & cdt)
|
||||
{
|
||||
using namespace std;
|
||||
// 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;
|
||||
typedef CGAL::Point_2<Kernel> Point_2;
|
||||
//typedef CGAL::Segment_2<Kernel> Segment_2;
|
||||
//typedef CGAL::Triangle_2<Kernel> Triangle_2;
|
||||
typedef CGAL::Triangulation_vertex_base_2<Kernel> TVB_2;
|
||||
typedef CGAL::Constrained_triangulation_face_base_2<Kernel> CTFB_2;
|
||||
typedef CGAL::Triangulation_data_structure_2<TVB_2,CTFB_2> TDS_2;
|
||||
typedef CGAL::Exact_intersections_tag Itag;
|
||||
typedef CGAL::Constrained_Delaunay_triangulation_2<Kernel,TDS_2,Itag>
|
||||
CDT_2;
|
||||
typedef CGAL::Constrained_triangulation_plus_2<CDT_2> CDT_plus_2;
|
||||
|
||||
// http://www.cgal.org/Manual/3.2/doc_html/cgal_manual/Triangulation_2/Chapter_main.html#Section_2D_Triangulations_Constrained_Plus
|
||||
// Plane of triangle A
|
||||
Plane_3 P(A.vertex(0),A.vertex(1),A.vertex(2));
|
||||
// Insert triangle into vertices
|
||||
typename CDT_plus_2::Vertex_handle corners[3];
|
||||
typedef size_t Index;
|
||||
for(Index i = 0;i<3;i++)
|
||||
{
|
||||
const Point_3 & p3 = A.vertex(i);
|
||||
const Point_2 & p2 = P.to_2d(p3);
|
||||
typename CDT_plus_2::Vertex_handle corner = cdt.insert(p2);
|
||||
corners[i] = corner;
|
||||
}
|
||||
// Insert triangle edges as constraints
|
||||
for(Index i = 0;i<3;i++)
|
||||
{
|
||||
cdt.insert_constraint( corners[(i+1)%3], corners[(i+2)%3]);
|
||||
}
|
||||
// Insert constraints for intersection objects
|
||||
for( const auto & obj : A_objects_3)
|
||||
{
|
||||
if(const Segment_3 *iseg = CGAL::object_cast<Segment_3 >(&obj))
|
||||
{
|
||||
// Add segment constraint
|
||||
cdt.insert_constraint(P.to_2d(iseg->vertex(0)),P.to_2d(iseg->vertex(1)));
|
||||
}else if(const Point_3 *ipoint = CGAL::object_cast<Point_3 >(&obj))
|
||||
{
|
||||
// Add point
|
||||
cdt.insert(P.to_2d(*ipoint));
|
||||
} else if(const Triangle_3 *itri = CGAL::object_cast<Triangle_3 >(&obj))
|
||||
{
|
||||
// Add 3 segment constraints
|
||||
cdt.insert_constraint(P.to_2d(itri->vertex(0)),P.to_2d(itri->vertex(1)));
|
||||
cdt.insert_constraint(P.to_2d(itri->vertex(1)),P.to_2d(itri->vertex(2)));
|
||||
cdt.insert_constraint(P.to_2d(itri->vertex(2)),P.to_2d(itri->vertex(0)));
|
||||
} else if(const std::vector<Point_3 > *polyp =
|
||||
CGAL::object_cast< std::vector<Point_3 > >(&obj))
|
||||
{
|
||||
//cerr<<REDRUM("Poly...")<<endl;
|
||||
const std::vector<Point_3 > & poly = *polyp;
|
||||
const Index m = poly.size();
|
||||
assert(m>=2);
|
||||
for(Index p = 0;p<m;p++)
|
||||
{
|
||||
const Index np = (p+1)%m;
|
||||
cdt.insert_constraint(P.to_2d(poly[p]),P.to_2d(poly[np]));
|
||||
}
|
||||
}else
|
||||
{
|
||||
cerr<<REDRUM("What is this object?!")<<endl;
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::copyleft::cgal::projected_delaunay<CGAL::Epeck>(CGAL::Triangle_3<CGAL::Epeck> const&, std::vector<CGAL::Object, std::allocator<CGAL::Object> > const&, CGAL::Constrained_triangulation_plus_2<CGAL::Constrained_Delaunay_triangulation_2<CGAL::Epeck, CGAL::Triangulation_data_structure_2<CGAL::Triangulation_vertex_base_2<CGAL::Epeck, CGAL::Triangulation_ds_vertex_base_2<void> >, CGAL::Constrained_triangulation_face_base_2<CGAL::Epeck, CGAL::Triangulation_face_base_2<CGAL::Epeck, CGAL::Triangulation_ds_face_base_2<void> > > >, CGAL::Exact_intersections_tag> >&);
|
||||
template void igl::copyleft::cgal::projected_delaunay<CGAL::Epick>(CGAL::Triangle_3<CGAL::Epick> const&, std::vector<CGAL::Object, std::allocator<CGAL::Object> > const&, CGAL::Constrained_triangulation_plus_2<CGAL::Constrained_Delaunay_triangulation_2<CGAL::Epick, CGAL::Triangulation_data_structure_2<CGAL::Triangulation_vertex_base_2<CGAL::Epick, CGAL::Triangulation_ds_vertex_base_2<void> >, CGAL::Constrained_triangulation_face_base_2<CGAL::Epick, CGAL::Triangulation_face_base_2<CGAL::Epick, CGAL::Triangulation_ds_face_base_2<void> > > >, CGAL::Exact_intersections_tag> >&);
|
||||
#endif
|
||||
46
src/igl/copyleft/cgal/projected_delaunay.h
Normal file
46
src/igl/copyleft/cgal/projected_delaunay.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// 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_PROJECTED_DELAUNAY_H
|
||||
#define IGL_COPYLEFT_CGAL_PROJECTED_DELAUNAY_H
|
||||
#include "../../igl_inline.h"
|
||||
#include "CGAL_includes.hpp"
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Compute 2D delaunay triangulation of a given 3d triangle and a list of
|
||||
// intersection objects (points,segments,triangles). CGAL uses an affine
|
||||
// projection rather than an isometric projection, so we're not guaranteed
|
||||
// that the 2D delaunay triangulation here will be a delaunay triangulation
|
||||
// in 3D.
|
||||
//
|
||||
// Inputs:
|
||||
// A triangle in 3D
|
||||
// A_objects_3 updated list of intersection objects for A
|
||||
// Outputs:
|
||||
// cdt Contrained delaunay triangulation in projected 2D plane
|
||||
template <typename Kernel>
|
||||
IGL_INLINE void projected_delaunay(
|
||||
const CGAL::Triangle_3<Kernel> & A,
|
||||
const std::vector<CGAL::Object> & A_objects_3,
|
||||
CGAL::Constrained_triangulation_plus_2<
|
||||
CGAL::Constrained_Delaunay_triangulation_2<
|
||||
Kernel,
|
||||
CGAL::Triangulation_data_structure_2<
|
||||
CGAL::Triangulation_vertex_base_2<Kernel>,
|
||||
CGAL::Constrained_triangulation_face_base_2<Kernel> >,
|
||||
CGAL::Exact_intersections_tag> > & cdt);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "projected_delaunay.cpp"
|
||||
#endif
|
||||
#endif
|
||||
324
src/igl/copyleft/cgal/propagate_winding_numbers.cpp
Normal file
324
src/igl/copyleft/cgal/propagate_winding_numbers.cpp
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
// 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 "propagate_winding_numbers.h"
|
||||
#include "../../extract_manifold_patches.h"
|
||||
#include "../../extract_non_manifold_edge_curves.h"
|
||||
#include "../../facet_components.h"
|
||||
#include "../../unique_edge_map.h"
|
||||
#include "../../piecewise_constant_winding_number.h"
|
||||
#include "../../writeOBJ.h"
|
||||
#include "../../writePLY.h"
|
||||
#include "../../get_seconds.h"
|
||||
#include "../../LinSpaced.h"
|
||||
#include "order_facets_around_edge.h"
|
||||
#include "outer_facet.h"
|
||||
#include "closest_facet.h"
|
||||
#include "assign.h"
|
||||
#include "extract_cells.h"
|
||||
#include "cell_adjacency.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <queue>
|
||||
|
||||
//#define PROPAGATE_WINDING_NUMBER_TIMING
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedL,
|
||||
typename DerivedW>
|
||||
IGL_INLINE bool igl::copyleft::cgal::propagate_winding_numbers(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedL>& labels,
|
||||
Eigen::PlainObjectBase<DerivedW>& W)
|
||||
{
|
||||
#ifdef PROPAGATE_WINDING_NUMBER_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 {
|
||||
std::cout << "propagate_winding_num." << label << ": "
|
||||
<< tictoc() << std::endl;
|
||||
};
|
||||
tictoc();
|
||||
#endif
|
||||
|
||||
Eigen::MatrixXi E, uE;
|
||||
Eigen::VectorXi EMAP;
|
||||
std::vector<std::vector<size_t> > uE2E;
|
||||
igl::unique_edge_map(F, E, uE, EMAP, uE2E);
|
||||
|
||||
Eigen::VectorXi P;
|
||||
const size_t num_patches = igl::extract_manifold_patches(F, EMAP, uE2E, P);
|
||||
|
||||
DerivedW per_patch_cells;
|
||||
const size_t num_cells =
|
||||
igl::copyleft::cgal::extract_cells(
|
||||
V, F, P, E, uE, uE2E, EMAP, per_patch_cells);
|
||||
#ifdef PROPAGATE_WINDING_NUMBER_TIMING
|
||||
log_time("cell_extraction");
|
||||
#endif
|
||||
|
||||
return propagate_winding_numbers(V, F,
|
||||
uE, uE2E,
|
||||
num_patches, P,
|
||||
num_cells, per_patch_cells,
|
||||
labels, W);
|
||||
}
|
||||
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename DerivedP,
|
||||
typename DerivedC,
|
||||
typename DerivedL,
|
||||
typename DerivedW>
|
||||
IGL_INLINE bool igl::copyleft::cgal::propagate_winding_numbers(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const size_t num_patches,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const size_t num_cells,
|
||||
const Eigen::PlainObjectBase<DerivedC>& C,
|
||||
const Eigen::PlainObjectBase<DerivedL>& labels,
|
||||
Eigen::PlainObjectBase<DerivedW>& W)
|
||||
{
|
||||
#ifdef PROPAGATE_WINDING_NUMBER_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 {
|
||||
std::cout << "propagate_winding_num." << label << ": "
|
||||
<< tictoc() << std::endl;
|
||||
};
|
||||
tictoc();
|
||||
#endif
|
||||
|
||||
bool valid = true;
|
||||
// https://github.com/libigl/libigl/issues/674
|
||||
if (!igl::piecewise_constant_winding_number(F, uE, uE2E))
|
||||
{
|
||||
assert(false && "Input mesh is not PWN");
|
||||
std::cerr << "Input mesh is not PWN!" << std::endl;
|
||||
valid = false;
|
||||
}
|
||||
|
||||
const size_t num_faces = F.rows();
|
||||
typedef std::tuple<typename DerivedC::Scalar, bool, size_t> CellConnection;
|
||||
std::vector<std::set<CellConnection> > cell_adj;
|
||||
igl::copyleft::cgal::cell_adjacency(C, num_cells, cell_adj);
|
||||
#ifdef PROPAGATE_WINDING_NUMBER_TIMING
|
||||
log_time("cell_connectivity");
|
||||
#endif
|
||||
|
||||
auto save_cell = [&](const std::string& filename, size_t cell_id) -> void{
|
||||
std::vector<size_t> faces;
|
||||
for (size_t i=0; i<num_patches; i++) {
|
||||
if ((C.row(i).array() == cell_id).any()) {
|
||||
for (size_t j=0; j<num_faces; j++) {
|
||||
if ((size_t)P[j] == i) {
|
||||
faces.push_back(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Eigen::MatrixXi cell_faces(faces.size(), 3);
|
||||
for (size_t i=0; i<faces.size(); i++) {
|
||||
cell_faces.row(i) = F.row(faces[i]);
|
||||
}
|
||||
Eigen::MatrixXd vertices;
|
||||
assign(V,vertices);
|
||||
writePLY(filename, vertices, cell_faces);
|
||||
};
|
||||
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
// Check for odd cycle.
|
||||
Eigen::VectorXi cell_labels(num_cells);
|
||||
cell_labels.setZero();
|
||||
Eigen::VectorXi parents(num_cells);
|
||||
parents.setConstant(-1);
|
||||
auto trace_parents = [&](size_t idx) -> std::list<size_t> {
|
||||
std::list<size_t> path;
|
||||
path.push_back(idx);
|
||||
while ((size_t)parents[path.back()] != path.back()) {
|
||||
path.push_back(parents[path.back()]);
|
||||
}
|
||||
return path;
|
||||
};
|
||||
for (size_t i=0; i<num_cells; i++) {
|
||||
if (cell_labels[i] == 0) {
|
||||
cell_labels[i] = 1;
|
||||
std::queue<size_t> Q;
|
||||
Q.push(i);
|
||||
parents[i] = i;
|
||||
while (!Q.empty()) {
|
||||
size_t curr_idx = Q.front();
|
||||
Q.pop();
|
||||
int curr_label = cell_labels[curr_idx];
|
||||
for (const auto& neighbor : cell_adj[curr_idx]) {
|
||||
if (cell_labels[std::get<0>(neighbor)] == 0)
|
||||
{
|
||||
cell_labels[std::get<0>(neighbor)] = curr_label * -1;
|
||||
Q.push(std::get<0>(neighbor));
|
||||
parents[std::get<0>(neighbor)] = curr_idx;
|
||||
} else
|
||||
{
|
||||
if (cell_labels[std::get<0>(neighbor)] != curr_label * -1)
|
||||
{
|
||||
std::cerr << "Odd cell cycle detected!" << std::endl;
|
||||
auto path = trace_parents(curr_idx);
|
||||
path.reverse();
|
||||
auto path2 = trace_parents(std::get<0>(neighbor));
|
||||
path.insert(path.end(), path2.begin(), path2.end());
|
||||
for (auto cell_id : path)
|
||||
{
|
||||
std::cout << cell_id << " ";
|
||||
std::stringstream filename;
|
||||
filename << "cell_" << cell_id << ".ply";
|
||||
save_cell(filename.str(), cell_id);
|
||||
}
|
||||
std::cout << std::endl;
|
||||
valid = false;
|
||||
}
|
||||
// Do not fail when odd cycle is detected because the resulting
|
||||
// integer winding number field, although inconsistent, may still
|
||||
// be used if the problem region is local and embedded within a
|
||||
// valid volume.
|
||||
//assert(cell_labels[std::get<0>(neighbor)] == curr_label * -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef PROPAGATE_WINDING_NUMBER_TIMING
|
||||
log_time("odd_cycle_check");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t outer_facet;
|
||||
bool flipped;
|
||||
Eigen::VectorXi I = igl::LinSpaced<Eigen::VectorXi>(num_faces, 0, num_faces-1);
|
||||
igl::copyleft::cgal::outer_facet(V, F, I, outer_facet, flipped);
|
||||
#ifdef PROPAGATE_WINDING_NUMBER_TIMING
|
||||
log_time("outer_facet");
|
||||
#endif
|
||||
|
||||
const size_t outer_patch = P[outer_facet];
|
||||
const size_t infinity_cell = C(outer_patch, flipped?1:0);
|
||||
|
||||
Eigen::VectorXi patch_labels(num_patches);
|
||||
const int INVALID = std::numeric_limits<int>::max();
|
||||
patch_labels.setConstant(INVALID);
|
||||
for (size_t i=0; i<num_faces; i++) {
|
||||
if (patch_labels[P[i]] == INVALID) {
|
||||
patch_labels[P[i]] = labels[i];
|
||||
} else {
|
||||
assert(patch_labels[P[i]] == labels[i]);
|
||||
}
|
||||
}
|
||||
assert((patch_labels.array() != INVALID).all());
|
||||
const size_t num_labels = patch_labels.maxCoeff()+1;
|
||||
|
||||
Eigen::MatrixXi per_cell_W(num_cells, num_labels);
|
||||
per_cell_W.setConstant(INVALID);
|
||||
per_cell_W.row(infinity_cell).setZero();
|
||||
std::queue<size_t> Q;
|
||||
Q.push(infinity_cell);
|
||||
while (!Q.empty()) {
|
||||
size_t curr_cell = Q.front();
|
||||
Q.pop();
|
||||
for (const auto& neighbor : cell_adj[curr_cell]) {
|
||||
size_t neighbor_cell, patch_idx;
|
||||
bool direction;
|
||||
std::tie(neighbor_cell, direction, patch_idx) = neighbor;
|
||||
if ((per_cell_W.row(neighbor_cell).array() == INVALID).any()) {
|
||||
per_cell_W.row(neighbor_cell) = per_cell_W.row(curr_cell);
|
||||
for (size_t i=0; i<num_labels; i++) {
|
||||
int inc = (patch_labels[patch_idx] == (int)i) ?
|
||||
(direction ? -1:1) :0;
|
||||
per_cell_W(neighbor_cell, i) =
|
||||
per_cell_W(curr_cell, i) + inc;
|
||||
}
|
||||
Q.push(neighbor_cell);
|
||||
} else {
|
||||
#ifndef NDEBUG
|
||||
// Checking for winding number consistency.
|
||||
// This check would inevitably fail for meshes that contain open
|
||||
// boundary or non-orientable. However, the inconsistent winding number
|
||||
// field would still be useful in some cases such as when problem region
|
||||
// is local and embedded within the volume. This, unfortunately, is the
|
||||
// best we can do because the problem of computing integer winding
|
||||
// number is ill-defined for open and non-orientable surfaces.
|
||||
for (size_t i=0; i<num_labels; i++) {
|
||||
if ((int)i == patch_labels[patch_idx]) {
|
||||
int inc = direction ? -1:1;
|
||||
//assert(per_cell_W(neighbor_cell, i) ==
|
||||
// per_cell_W(curr_cell, i) + inc);
|
||||
} else {
|
||||
//assert(per_cell_W(neighbor_cell, i) ==
|
||||
// per_cell_W(curr_cell, i));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef PROPAGATE_WINDING_NUMBER_TIMING
|
||||
log_time("propagate_winding_number");
|
||||
#endif
|
||||
|
||||
W.resize(num_faces, num_labels*2);
|
||||
for (size_t i=0; i<num_faces; i++)
|
||||
{
|
||||
const size_t patch = P[i];
|
||||
const size_t positive_cell = C(patch, 0);
|
||||
const size_t negative_cell = C(patch, 1);
|
||||
for (size_t j=0; j<num_labels; j++) {
|
||||
W(i,j*2 ) = per_cell_W(positive_cell, j);
|
||||
W(i,j*2+1) = per_cell_W(negative_cell, j);
|
||||
}
|
||||
}
|
||||
#ifdef PROPAGATE_WINDING_NUMBER_TIMING
|
||||
log_time("store_result");
|
||||
#endif
|
||||
return valid;
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template bool igl::copyleft::cgal::propagate_winding_numbers<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned long, 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::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, unsigned long, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, unsigned long, 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 bool igl::copyleft::cgal::propagate_winding_numbers<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned long, 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::Lazy_exact_nt<CGAL::Gmpq>, -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&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, unsigned long, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, unsigned long, 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> >&);
|
||||
template bool igl::copyleft::cgal::propagate_winding_numbers<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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::Lazy_exact_nt<CGAL::Gmpq>, -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 bool igl::copyleft::cgal::propagate_winding_numbers<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, unsigned __int64, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, unsigned __int64, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &);
|
||||
template bool igl::copyleft::cgal::propagate_winding_numbers<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, unsigned __int64, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, unsigned __int64, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &);
|
||||
#endif
|
||||
#endif
|
||||
103
src/igl/copyleft/cgal/propagate_winding_numbers.h
Normal file
103
src/igl/copyleft/cgal/propagate_winding_numbers.h
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
// 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_PROPAGATE_WINDING_NUMBERS_H
|
||||
#define IGL_COPYLEFT_CGAL_PROPAGATE_WINDING_NUMBERS_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
|
||||
// The following methods compute the winding number on each side of each facet
|
||||
// or patch of a 3D mesh. The input mesh is valid if it splits the ambient
|
||||
// space, R^3, into subspaces with constant integer winding numbers. That is
|
||||
// the input mesh should be closed and for each directed edge the number of
|
||||
// clockwise facing facets should equal the number of counterclockwise facing
|
||||
// facets.
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// TODO: This shouldn't need to be in igl::copyleft::cgal, it should
|
||||
// instead take as input an index of the ambient cell and the winding
|
||||
// number vector there.
|
||||
//
|
||||
// Compute winding number on each side of the face. The input mesh
|
||||
// could contain multiple connected components. The input mesh must
|
||||
// represent the boundary of a valid 3D volume, which means it is
|
||||
// closed, consistently oriented and induces integer winding numbers.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions.
|
||||
// F #F by 3 list of triangle indices into V.
|
||||
// labels #F list of facet labels ranging from 0 to k-1.
|
||||
// Output:
|
||||
// W #F by k*2 list of winding numbers. ``W(i,j*2)`` is the winding
|
||||
// number on the positive side of facet ``i`` with respect to the
|
||||
// facets labeled ``j``. Similarly, ``W(i,j*2+1)`` is the winding
|
||||
// number on the negative side of facet ``i`` with respect to the
|
||||
// facets labeled ``j``.
|
||||
// Returns true iff the input induces a piecewise-constant winding number
|
||||
// field.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedL,
|
||||
typename DerivedW>
|
||||
IGL_INLINE bool propagate_winding_numbers(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedL>& labels,
|
||||
Eigen::PlainObjectBase<DerivedW>& W);
|
||||
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions.
|
||||
// F #F by 3 list of triangle indices into V.
|
||||
// uE #uE by 2 list of vertex_indices, represents undirected edges.
|
||||
// uE2E #uE list of lists that maps uE to E. (a one-to-many map)
|
||||
// num_patches number of patches
|
||||
// P #F list of patch ids.
|
||||
// num_cells number of cells
|
||||
// C #P by 2 list of cell ids on each side of each patch.
|
||||
// labels #F list of facet labels ranging from 0 to k-1.
|
||||
// Output:
|
||||
// W #F by k*2 list of winding numbers. ``W(i,j*2)`` is the winding
|
||||
// number on the positive side of facet ``i`` with respect to the
|
||||
// facets labeled ``j``. Similarly, ``W(i,j*2+1)`` is the winding
|
||||
// number on the negative side of facet ``i`` with respect to the
|
||||
// facets labeled ``j``.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename DerivedP,
|
||||
typename DerivedC,
|
||||
typename DerivedL,
|
||||
typename DerivedW>
|
||||
IGL_INLINE bool propagate_winding_numbers(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const size_t num_patches,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const size_t num_cells,
|
||||
const Eigen::PlainObjectBase<DerivedC>& C,
|
||||
const Eigen::PlainObjectBase<DerivedL>& labels,
|
||||
Eigen::PlainObjectBase<DerivedW>& W);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "propagate_winding_numbers.cpp"
|
||||
#endif
|
||||
#endif
|
||||
26
src/igl/copyleft/cgal/read_triangle_mesh.cpp
Normal file
26
src/igl/copyleft/cgal/read_triangle_mesh.cpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// 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 "read_triangle_mesh.h"
|
||||
#include "assign.h"
|
||||
#include "../../read_triangle_mesh.h"
|
||||
|
||||
template <typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE bool igl::copyleft::cgal::read_triangle_mesh(
|
||||
const std::string str,
|
||||
Eigen::PlainObjectBase<DerivedV>& V,
|
||||
Eigen::PlainObjectBase<DerivedF>& F)
|
||||
{
|
||||
Eigen::MatrixXd Vd;
|
||||
bool ret = igl::read_triangle_mesh(str,Vd,F);
|
||||
if(ret)
|
||||
{
|
||||
assign(Vd,V);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
42
src/igl/copyleft/cgal/read_triangle_mesh.h
Normal file
42
src/igl/copyleft/cgal/read_triangle_mesh.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// 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_READ_TRIANGLE_MESH_H
|
||||
#define IGL_COPYLEFT_CGAL_READ_TRIANGLE_MESH_H
|
||||
#include "../../igl_inline.h"
|
||||
|
||||
#include <Eigen/Core>
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Simple wrapper, reads floating point precision but assigns to
|
||||
// DerivedV::Scalar which may be a CGAL type
|
||||
//
|
||||
// Inputs:
|
||||
// str path to file
|
||||
// Outputs:
|
||||
// V eigen double matrix #V by 3
|
||||
// F eigen int matrix #F by 3
|
||||
// Returns true iff success
|
||||
template <typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE bool read_triangle_mesh(
|
||||
const std::string str,
|
||||
Eigen::PlainObjectBase<DerivedV>& V,
|
||||
Eigen::PlainObjectBase<DerivedF>& F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "read_triangle_mesh.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
117
src/igl/copyleft/cgal/relabel_small_immersed_cells.cpp
Normal file
117
src/igl/copyleft/cgal/relabel_small_immersed_cells.cpp
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
// 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 "relabel_small_immersed_cells.h"
|
||||
#include "../../centroid.h"
|
||||
#include "assign.h"
|
||||
#include "cell_adjacency.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename DerivedC,
|
||||
typename FT,
|
||||
typename DerivedW>
|
||||
IGL_INLINE void igl::copyleft::cgal::relabel_small_immersed_cells(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const size_t num_patches,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const size_t num_cells,
|
||||
const Eigen::PlainObjectBase<DerivedC>& C,
|
||||
const FT vol_threashold,
|
||||
Eigen::PlainObjectBase<DerivedW>& W)
|
||||
{
|
||||
const size_t num_vertices = V.rows();
|
||||
const size_t num_faces = F.rows();
|
||||
typedef std::tuple<typename DerivedC::Scalar, bool, size_t> CellConnection;
|
||||
std::vector<std::set<CellConnection> > cell_adj;
|
||||
igl::copyleft::cgal::cell_adjacency(C, num_cells, cell_adj);
|
||||
|
||||
Eigen::MatrixXd VV;
|
||||
assign(V,VV);
|
||||
|
||||
auto compute_cell_volume = [&](size_t cell_id) {
|
||||
std::vector<short> is_involved(num_patches, 0);
|
||||
for (size_t i=0; i<num_patches; i++) {
|
||||
if (C(i,0) == cell_id) {
|
||||
// cell is on positive side of patch i.
|
||||
is_involved[i] = 1;
|
||||
}
|
||||
if (C(i,1) == cell_id) {
|
||||
// cell is on negative side of patch i.
|
||||
is_involved[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<size_t> involved_positive_faces;
|
||||
std::vector<size_t> involved_negative_faces;
|
||||
for (size_t i=0; i<num_faces; i++) {
|
||||
switch (is_involved[P[i]]) {
|
||||
case 1:
|
||||
involved_negative_faces.push_back(i);
|
||||
break;
|
||||
case -1:
|
||||
involved_positive_faces.push_back(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const size_t num_positive_faces = involved_positive_faces.size();
|
||||
const size_t num_negative_faces = involved_negative_faces.size();
|
||||
DerivedF selected_faces(num_positive_faces + num_negative_faces, 3);
|
||||
for (size_t i=0; i<num_positive_faces; i++) {
|
||||
selected_faces.row(i) = F.row(involved_positive_faces[i]);
|
||||
}
|
||||
for (size_t i=0; i<num_negative_faces; i++) {
|
||||
selected_faces.row(num_positive_faces+i) =
|
||||
F.row(involved_negative_faces[i]).reverse();
|
||||
}
|
||||
|
||||
Eigen::VectorXd c(3);
|
||||
double vol;
|
||||
igl::centroid(VV, selected_faces, c, vol);
|
||||
return vol;
|
||||
};
|
||||
|
||||
std::vector<typename DerivedV::Scalar> cell_volumes(num_cells);
|
||||
for (size_t i=0; i<num_cells; i++) {
|
||||
cell_volumes[i] = compute_cell_volume(i);
|
||||
}
|
||||
|
||||
std::vector<typename DerivedW::Scalar> cell_values(num_cells);
|
||||
for (size_t i=0; i<num_faces; i++) {
|
||||
cell_values[C(P[i], 0)] = W(i, 0);
|
||||
cell_values[C(P[i], 1)] = W(i, 1);
|
||||
}
|
||||
|
||||
for (size_t i=1; i<num_cells; i++) {
|
||||
std::cout << cell_volumes[i] << std::endl;
|
||||
if (cell_volumes[i] >= vol_threashold) continue;
|
||||
std::set<typename DerivedW::Scalar> neighbor_values;
|
||||
const auto neighbors = cell_adj[i];
|
||||
for (const auto& entry : neighbors) {
|
||||
const auto& j = std::get<0>(entry);
|
||||
neighbor_values.insert(cell_values[j]);
|
||||
}
|
||||
// If cell i is immersed, assign its value to be the immersed value.
|
||||
if (neighbor_values.size() == 1) {
|
||||
cell_values[i] = *neighbor_values.begin();
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i=0; i<num_faces; i++) {
|
||||
W(i,0) = cell_values[C(P[i], 0)];
|
||||
W(i,1) = cell_values[C(P[i], 1)];
|
||||
}
|
||||
}
|
||||
|
||||
59
src/igl/copyleft/cgal/relabel_small_immersed_cells.h
Normal file
59
src/igl/copyleft/cgal/relabel_small_immersed_cells.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// 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_RELABEL_SMALL_IMMERSED_CELLS
|
||||
#define IGL_RELABEL_SMALL_IMMERSED_CELLS
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions.
|
||||
// F #F by 3 list of triangle indices into V.
|
||||
// num_patches number of patches
|
||||
// P #F list of patch ids.
|
||||
// num_cells number of cells
|
||||
// C #P by 2 list of cell ids on each side of each patch.
|
||||
// vol_threshold Volume threshold, cells smaller than this
|
||||
// and is completely immersed will be relabeled.
|
||||
//
|
||||
// In/Output:
|
||||
// W #F by 2 cell labels. W(i,0) is the label on the positive side of
|
||||
// face i, W(i,1) is the label on the negative side of face i. W
|
||||
// will be modified in place by this method.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename DerivedC,
|
||||
typename FT,
|
||||
typename DerivedW>
|
||||
IGL_INLINE void relabel_small_immersed_cells(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const size_t num_patches,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const size_t num_cells,
|
||||
const Eigen::PlainObjectBase<DerivedC>& C,
|
||||
const FT vol_threashold,
|
||||
Eigen::PlainObjectBase<DerivedW>& W);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "relabel_small_immersed_cells.cpp"
|
||||
#endif
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue