Merged branch 'dev_native' into lm_sla_supports_auto

Added igl library files
This commit is contained in:
Lukas Matena 2018-10-26 15:45:52 +02:00
commit 7681d00ee5
2865 changed files with 142806 additions and 22325 deletions

View 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.

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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++;
// }
// }
// };
}

View 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

View 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

View 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

View 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]);
}
}

View 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

View 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);
}
}
}
}

View 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

View 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

View 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

View 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);
}

View 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

View 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";
}
}

View 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

View 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

View 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

View 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";
}
}

View 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

View 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

View 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

View 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

View 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

View 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);
}

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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";
}
}

View 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

View 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";
}
}

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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;
}

View 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

View 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);
}

View 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

View 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);
}
}
}
}

View 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

View 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

View 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

View 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();
}

View 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

View file

@ -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

View 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

View 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;
}
}
}

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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;
}

View 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

View 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)];
}
}

View 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