mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-28 03:01:17 -06:00
Building igl statically and moving to the dep scripts
Fixing dep build script on Windows and removing some warnings. Use bundled igl by default. Not building with the dependency scripts if not explicitly stated. This way, it will stay in Fix the libigl patch to include C source files in header only mode.
This commit is contained in:
parent
89e39e3895
commit
2ae2672ee9
1095 changed files with 181 additions and 5 deletions
14
src/libigl/igl/copyleft/README.md
Normal file
14
src/libigl/igl/copyleft/README.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
## IGL copyleft subdirectory
|
||||
|
||||
Functions in the `include/igl/copyleft/` subdirectory are in the
|
||||
`igl::copyleft::` namespace to indicate that they are under a more aggressive
|
||||
[copyleft](https://en.wikipedia.org/wiki/Copyleft) than
|
||||
[MPL2](https://en.wikipedia.org/wiki/Mozilla_Public_License) used for the main
|
||||
`include/igl` directory and `igl::` namespace. Most notably, this subdirectory
|
||||
includes code that is under
|
||||
[GPL](https://en.wikipedia.org/wiki/GNU_General_Public_License).
|
||||
|
||||
Typically a company planning on developing software without releasing its
|
||||
source code will avoid or purchase licenses for such dependencies. If you do
|
||||
obtain such a license for the dependencies employed here, you are free to use
|
||||
the libigl functions here as per their MPL2 license.
|
||||
167
src/libigl/igl/copyleft/cgal/BinaryWindingNumberOperations.h
Normal file
167
src/libigl/igl/copyleft/cgal/BinaryWindingNumberOperations.h
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
#ifndef IGL_COPYLEFT_CGAL_BINARY_WINDING_NUMBER_OPERATIONS_H
|
||||
#define IGL_COPYLEFT_CGAL_BINARY_WINDING_NUMBER_OPERATIONS_H
|
||||
|
||||
#include <stdexcept>
|
||||
#include "../../igl_inline.h"
|
||||
#include "../../MeshBooleanType.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
// TODO: This is not written according to libigl style. These should be
|
||||
// function handles.
|
||||
//
|
||||
// Why is this templated on DerivedW
|
||||
//
|
||||
// These are all generalized to n-ary operations
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
template <igl::MeshBooleanType Op>
|
||||
class BinaryWindingNumberOperations {
|
||||
public:
|
||||
template<typename DerivedW>
|
||||
typename DerivedW::Scalar operator()(
|
||||
const Eigen::PlainObjectBase<DerivedW>& /*win_nums*/) const {
|
||||
throw (std::runtime_error("not implemented!"));
|
||||
}
|
||||
};
|
||||
|
||||
// A ∪ B ∪ ... ∪ Z
|
||||
template <>
|
||||
class BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_UNION> {
|
||||
public:
|
||||
template<typename DerivedW>
|
||||
typename DerivedW::Scalar operator()(
|
||||
const Eigen::PlainObjectBase<DerivedW>& win_nums) const
|
||||
{
|
||||
for(int i = 0;i<win_nums.size();i++)
|
||||
{
|
||||
if(win_nums(i) > 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// A ∩ B ∩ ... ∩ Z
|
||||
template <>
|
||||
class BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_INTERSECT> {
|
||||
public:
|
||||
template<typename DerivedW>
|
||||
typename DerivedW::Scalar operator()(
|
||||
const Eigen::PlainObjectBase<DerivedW>& win_nums) const
|
||||
{
|
||||
for(int i = 0;i<win_nums.size();i++)
|
||||
{
|
||||
if(win_nums(i)<=0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// A \ B \ ... \ Z = A \ (B ∪ ... ∪ Z)
|
||||
template <>
|
||||
class BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_MINUS> {
|
||||
public:
|
||||
template<typename DerivedW>
|
||||
typename DerivedW::Scalar operator()(
|
||||
const Eigen::PlainObjectBase<DerivedW>& win_nums) const
|
||||
{
|
||||
assert(win_nums.size()>1);
|
||||
// Union of objects 1 through n-1
|
||||
bool union_rest = false;
|
||||
for(int i = 1;i<win_nums.size();i++)
|
||||
{
|
||||
union_rest = union_rest || win_nums(i) > 0;
|
||||
if(union_rest) break;
|
||||
}
|
||||
// Must be in object 0 and not in union of objects 1 through n-1
|
||||
return win_nums(0) > 0 && !union_rest;
|
||||
}
|
||||
};
|
||||
|
||||
// A ∆ B ∆ ... ∆ Z (equivalent to set inside odd number of objects)
|
||||
template <>
|
||||
class BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_XOR> {
|
||||
public:
|
||||
template<typename DerivedW>
|
||||
typename DerivedW::Scalar operator()(
|
||||
const Eigen::PlainObjectBase<DerivedW>& win_nums) const
|
||||
{
|
||||
// If inside an odd number of objects
|
||||
int count = 0;
|
||||
for(int i = 0;i<win_nums.size();i++)
|
||||
{
|
||||
if(win_nums(i) > 0) count++;
|
||||
}
|
||||
return count % 2 == 1;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_RESOLVE> {
|
||||
public:
|
||||
template<typename DerivedW>
|
||||
typename DerivedW::Scalar operator()(
|
||||
const Eigen::PlainObjectBase<DerivedW>& /*win_nums*/) const {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
typedef BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_UNION> BinaryUnion;
|
||||
typedef BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_INTERSECT> BinaryIntersect;
|
||||
typedef BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_MINUS> BinaryMinus;
|
||||
typedef BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_XOR> BinaryXor;
|
||||
typedef BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_RESOLVE> BinaryResolve;
|
||||
|
||||
enum KeeperType {
|
||||
KEEP_INSIDE,
|
||||
KEEP_ALL
|
||||
};
|
||||
|
||||
template<KeeperType T>
|
||||
class WindingNumberFilter {
|
||||
public:
|
||||
template<typename DerivedW>
|
||||
short operator()(
|
||||
const Eigen::PlainObjectBase<DerivedW>& /*win_nums*/) const {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class WindingNumberFilter<KEEP_INSIDE> {
|
||||
public:
|
||||
template<typename T>
|
||||
short operator()(T out_w, T in_w) const {
|
||||
if (in_w > 0 && out_w <= 0) return 1;
|
||||
else if (in_w <= 0 && out_w > 0) return -1;
|
||||
else return 0;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class WindingNumberFilter<KEEP_ALL> {
|
||||
public:
|
||||
template<typename T>
|
||||
short operator()(T /*out_w*/, T /*in_w*/) const {
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
typedef WindingNumberFilter<KEEP_INSIDE> KeepInside;
|
||||
typedef WindingNumberFilter<KEEP_ALL> KeepAll;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
50
src/libigl/igl/copyleft/cgal/CGAL_includes.hpp
Normal file
50
src/libigl/igl/copyleft/cgal/CGAL_includes.hpp
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_CGAL_INCLUDES_H
|
||||
#define IGL_CGAL_INCLUDES_H
|
||||
|
||||
// This causes unknown bugs during intersection meshing:
|
||||
//// http://www.alecjacobson.com/weblog/?p=4291
|
||||
//#define CGAL_INTERSECTION_VERSION 1
|
||||
// Use this instead to mute errors resulting from bad CGAL assertions
|
||||
#define CGAL_KERNEL_NO_ASSERTIONS
|
||||
// Triangle triangle intersection
|
||||
#include <CGAL/intersections.h>
|
||||
// THIS CANNOT BE INCLUDED IN THE SAME FILE AS <CGAL/intersections.h>
|
||||
// #include <CGAL/Boolean_set_operations_2.h>
|
||||
|
||||
// Constrained Delaunay Triangulation types
|
||||
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
|
||||
#include <CGAL/Constrained_triangulation_plus_2.h>
|
||||
|
||||
// Axis-align boxes for all-pairs self-intersection detection
|
||||
#include <CGAL/point_generators_3.h>
|
||||
#include <CGAL/Bbox_3.h>
|
||||
#include <CGAL/box_intersection_d.h>
|
||||
#include <CGAL/function_objects.h>
|
||||
#include <CGAL/Join_input_iterator.h>
|
||||
#include <CGAL/algorithm.h>
|
||||
#include <vector>
|
||||
|
||||
// Axis-aligned bounding box tree for tet tri intersection
|
||||
#include <CGAL/AABB_tree.h>
|
||||
#include <CGAL/AABB_traits.h>
|
||||
#include <CGAL/AABB_triangle_primitive.h>
|
||||
|
||||
// Boolean operations
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
// Is this actually used?
|
||||
//#include <CGAL/Nef_polyhedron_3.h>
|
||||
|
||||
// Delaunay Triangulation in 3D
|
||||
#include <CGAL/Delaunay_triangulation_3.h>
|
||||
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#endif
|
||||
189
src/libigl/igl/copyleft/cgal/CSGTree.h
Normal file
189
src/libigl/igl/copyleft/cgal/CSGTree.h
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_CSG_TREE_H
|
||||
#define IGL_COPYLEFT_CGAL_CSG_TREE_H
|
||||
|
||||
#include "../../MeshBooleanType.h"
|
||||
#include "string_to_mesh_boolean_type.h"
|
||||
#include "mesh_boolean.h"
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/number_utils.h>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Class for defining and computing a constructive solid geometry result
|
||||
// out of a tree of boolean operations on "solid" triangle meshes.
|
||||
//
|
||||
//template <typename DerivedF>
|
||||
class CSGTree
|
||||
{
|
||||
public:
|
||||
typedef CGAL::Epeck::FT ExactScalar;
|
||||
//typedef Eigen::PlainObjectBase<DerivedF> POBF;
|
||||
typedef Eigen::MatrixXi POBF;
|
||||
typedef POBF::Index FIndex;
|
||||
typedef Eigen::Matrix<ExactScalar,Eigen::Dynamic,3> MatrixX3E;
|
||||
typedef Eigen::Matrix<FIndex,Eigen::Dynamic,1> VectorJ;
|
||||
private:
|
||||
// Resulting mesh
|
||||
MatrixX3E m_V;
|
||||
POBF m_F;
|
||||
VectorJ m_J;
|
||||
// Number of birth faces in A + those in B. I.e. sum of original "leaf"
|
||||
// faces involved in result.
|
||||
size_t m_number_of_birth_faces;
|
||||
public:
|
||||
CSGTree()
|
||||
{
|
||||
}
|
||||
//typedef Eigen::MatrixXd MatrixX3E;
|
||||
//typedef Eigen::MatrixXi POBF;
|
||||
// http://stackoverflow.com/a/3279550/148668
|
||||
CSGTree(const CSGTree & other)
|
||||
:
|
||||
// copy things
|
||||
m_V(other.m_V),
|
||||
// This is an issue if m_F is templated
|
||||
// https://forum.kde.org/viewtopic.php?f=74&t=128414
|
||||
m_F(other.m_F),
|
||||
m_J(other.m_J),
|
||||
m_number_of_birth_faces(other.m_number_of_birth_faces)
|
||||
{
|
||||
}
|
||||
// copy-swap idiom
|
||||
friend void swap(CSGTree& first, CSGTree& second)
|
||||
{
|
||||
using std::swap;
|
||||
// swap things
|
||||
swap(first.m_V,second.m_V);
|
||||
// This is an issue if m_F is templated, similar to
|
||||
// https://forum.kde.org/viewtopic.php?f=74&t=128414
|
||||
swap(first.m_F,second.m_F);
|
||||
swap(first.m_J,second.m_J);
|
||||
swap(first.m_number_of_birth_faces,second.m_number_of_birth_faces);
|
||||
}
|
||||
// Pass-by-value (aka copy)
|
||||
CSGTree& operator=(CSGTree other)
|
||||
{
|
||||
swap(*this,other);
|
||||
return *this;
|
||||
}
|
||||
CSGTree(CSGTree&& other):
|
||||
// initialize via default constructor
|
||||
CSGTree()
|
||||
{
|
||||
swap(*this,other);
|
||||
}
|
||||
// Construct and compute a boolean operation on existing CSGTree nodes.
|
||||
//
|
||||
// Inputs:
|
||||
// A Solid result of previous CSG operation (or identity, see below)
|
||||
// B Solid result of previous CSG operation (or identity, see below)
|
||||
// type type of mesh boolean to compute
|
||||
CSGTree(
|
||||
const CSGTree & A,
|
||||
const CSGTree & B,
|
||||
const MeshBooleanType & type)
|
||||
{
|
||||
// conduct boolean operation
|
||||
mesh_boolean(A.V(),A.F(),B.V(),B.F(),type,m_V,m_F,m_J);
|
||||
// reindex m_J
|
||||
std::for_each(m_J.data(),m_J.data()+m_J.size(),
|
||||
[&](typename VectorJ::Scalar & j) -> void
|
||||
{
|
||||
if(j < A.F().rows())
|
||||
{
|
||||
j = A.J()(j);
|
||||
}else
|
||||
{
|
||||
assert(j<(A.F().rows()+B.F().rows()));
|
||||
j = A.number_of_birth_faces()+(B.J()(j-A.F().rows()));
|
||||
}
|
||||
});
|
||||
m_number_of_birth_faces =
|
||||
A.number_of_birth_faces() + B.number_of_birth_faces();
|
||||
}
|
||||
// Overload using string for type
|
||||
CSGTree(
|
||||
const CSGTree & A,
|
||||
const CSGTree & B,
|
||||
const std::string & s):
|
||||
CSGTree(A,B,string_to_mesh_boolean_type(s))
|
||||
{
|
||||
// do nothing (all done in constructor).
|
||||
}
|
||||
// "Leaf" node with identity operation on assumed "solid" mesh (V,F)
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of mesh vertices (in any precision, will be
|
||||
// converted to exact)
|
||||
// F #F by 3 list of mesh face indices into V
|
||||
template <typename DerivedV>
|
||||
CSGTree(const Eigen::PlainObjectBase<DerivedV> & V, const POBF & F)//:
|
||||
// Possible Eigen bug:
|
||||
// https://forum.kde.org/viewtopic.php?f=74&t=128414
|
||||
//m_V(V.template cast<ExactScalar>()),m_F(F)
|
||||
{
|
||||
m_V = V.template cast<ExactScalar>();
|
||||
m_F = F;
|
||||
// number of faces
|
||||
m_number_of_birth_faces = m_F.rows();
|
||||
// identity birth index
|
||||
m_J = VectorJ::LinSpaced(
|
||||
m_number_of_birth_faces,0,m_number_of_birth_faces-1);
|
||||
}
|
||||
// Returns reference to resulting mesh vertices m_V in exact scalar
|
||||
// representation
|
||||
const MatrixX3E & V() const
|
||||
{
|
||||
return m_V;
|
||||
}
|
||||
// Returns mesh vertices in the desired output type, casting when
|
||||
// appropriate to floating precision.
|
||||
template <typename DerivedV>
|
||||
DerivedV cast_V() const
|
||||
{
|
||||
DerivedV dV;
|
||||
dV.resize(m_V.rows(),m_V.cols());
|
||||
for(int i = 0;i<m_V.rows();i++)
|
||||
{
|
||||
for(int j = 0;j<m_V.cols();j++)
|
||||
{
|
||||
dV(i,j) = CGAL::to_double(m_V(i,j));
|
||||
}
|
||||
}
|
||||
return dV;
|
||||
}
|
||||
// Returns reference to resulting mesh faces m_F
|
||||
const POBF & F() const
|
||||
{
|
||||
return m_F;
|
||||
}
|
||||
// Returns reference to "birth parents" indices into [F1;F2;...;Fn]
|
||||
// where F1, ... , Fn are the face lists of the leaf ("original") input
|
||||
// meshes.
|
||||
const VectorJ & J() const
|
||||
{
|
||||
return m_J;
|
||||
}
|
||||
// The number of leaf faces = #F1 + #F2 + ... + #Fn
|
||||
const size_t & number_of_birth_faces() const
|
||||
{
|
||||
return m_number_of_birth_faces;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
36
src/libigl/igl/copyleft/cgal/RemeshSelfIntersectionsParam.h
Normal file
36
src/libigl/igl/copyleft/cgal/RemeshSelfIntersectionsParam.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_REMESH_SELF_INTERSECTIONS_PARAM_H
|
||||
#define IGL_COPYLEFT_CGAL_REMESH_SELF_INTERSECTIONS_PARAM_H
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Optional Parameters
|
||||
// DetectOnly Only compute IF, leave VV and FF alone
|
||||
struct RemeshSelfIntersectionsParam
|
||||
{
|
||||
bool detect_only;
|
||||
bool first_only;
|
||||
bool stitch_all;
|
||||
inline RemeshSelfIntersectionsParam(
|
||||
bool _detect_only=false,
|
||||
bool _first_only=false,
|
||||
bool _stitch_all=false):
|
||||
detect_only(_detect_only),
|
||||
first_only(_first_only),
|
||||
stitch_all(_stitch_all){};
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
939
src/libigl/igl/copyleft/cgal/SelfIntersectMesh.h
Normal file
939
src/libigl/igl/copyleft/cgal/SelfIntersectMesh.h
Normal file
|
|
@ -0,0 +1,939 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_SELFINTERSECTMESH_H
|
||||
#define IGL_COPYLEFT_CGAL_SELFINTERSECTMESH_H
|
||||
|
||||
#include "CGAL_includes.hpp"
|
||||
#include "RemeshSelfIntersectionsParam.h"
|
||||
#include "../../unique.h"
|
||||
|
||||
#include <Eigen/Dense>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
|
||||
//#define IGL_SELFINTERSECTMESH_DEBUG
|
||||
#ifndef IGL_FIRST_HIT_EXCEPTION
|
||||
#define IGL_FIRST_HIT_EXCEPTION 10
|
||||
#endif
|
||||
|
||||
// The easiest way to keep track of everything is to use a class
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Kernel is a CGAL kernel like:
|
||||
// CGAL::Exact_predicates_inexact_constructions_kernel
|
||||
// or
|
||||
// CGAL::Exact_predicates_exact_constructions_kernel
|
||||
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedIF,
|
||||
typename DerivedJ,
|
||||
typename DerivedIM>
|
||||
class SelfIntersectMesh
|
||||
{
|
||||
typedef
|
||||
SelfIntersectMesh<
|
||||
Kernel,
|
||||
DerivedV,
|
||||
DerivedF,
|
||||
DerivedVV,
|
||||
DerivedFF,
|
||||
DerivedIF,
|
||||
DerivedJ,
|
||||
DerivedIM> Self;
|
||||
public:
|
||||
// 3D Primitives
|
||||
typedef CGAL::Point_3<Kernel> Point_3;
|
||||
typedef CGAL::Segment_3<Kernel> Segment_3;
|
||||
typedef CGAL::Triangle_3<Kernel> Triangle_3;
|
||||
typedef CGAL::Plane_3<Kernel> Plane_3;
|
||||
typedef CGAL::Tetrahedron_3<Kernel> Tetrahedron_3;
|
||||
// 2D Primitives
|
||||
typedef CGAL::Point_2<Kernel> Point_2;
|
||||
typedef CGAL::Segment_2<Kernel> Segment_2;
|
||||
typedef CGAL::Triangle_2<Kernel> Triangle_2;
|
||||
// 2D Constrained Delaunay Triangulation types
|
||||
typedef CGAL::Exact_intersections_tag Itag;
|
||||
// Axis-align boxes for all-pairs self-intersection detection
|
||||
typedef std::vector<Triangle_3> Triangles;
|
||||
typedef typename Triangles::iterator TrianglesIterator;
|
||||
typedef typename Triangles::const_iterator TrianglesConstIterator;
|
||||
typedef
|
||||
CGAL::Box_intersection_d::Box_with_handle_d<double,3,TrianglesIterator>
|
||||
Box;
|
||||
|
||||
// Input mesh
|
||||
const Eigen::MatrixBase<DerivedV> & V;
|
||||
const Eigen::MatrixBase<DerivedF> & F;
|
||||
// Number of self-intersecting triangle pairs
|
||||
typedef typename DerivedF::Index Index;
|
||||
Index count;
|
||||
typedef std::vector<std::pair<Index, CGAL::Object>> ObjectList;
|
||||
// Using a vector here makes this **not** output sensitive
|
||||
Triangles T;
|
||||
typedef std::vector<Index> IndexList;
|
||||
IndexList lIF;
|
||||
// #F-long list of faces with intersections mapping to the order in
|
||||
// which they were first found
|
||||
std::map<Index,ObjectList> offending;
|
||||
// Make a short name for the edge map's key
|
||||
typedef std::pair<Index,Index> EMK;
|
||||
// Make a short name for the type stored at each edge, the edge map's
|
||||
// value
|
||||
typedef std::vector<Index> EMV;
|
||||
// Make a short name for the edge map
|
||||
typedef std::map<EMK,EMV> EdgeMap;
|
||||
// Maps edges of offending faces to all incident offending faces
|
||||
std::vector<std::pair<TrianglesIterator, TrianglesIterator> >
|
||||
candidate_triangle_pairs;
|
||||
|
||||
public:
|
||||
RemeshSelfIntersectionsParam params;
|
||||
public:
|
||||
// Constructs (VV,FF) a new mesh with self-intersections of (V,F)
|
||||
// subdivided
|
||||
//
|
||||
// See also: remesh_self_intersections.h
|
||||
inline SelfIntersectMesh(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const RemeshSelfIntersectionsParam & params,
|
||||
Eigen::PlainObjectBase<DerivedVV> & VV,
|
||||
Eigen::PlainObjectBase<DerivedFF> & FF,
|
||||
Eigen::PlainObjectBase<DerivedIF> & IF,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J,
|
||||
Eigen::PlainObjectBase<DerivedIM> & IM);
|
||||
private:
|
||||
// Helper function to mark a face as offensive
|
||||
//
|
||||
// Inputs:
|
||||
// f index of face in F
|
||||
inline void mark_offensive(const Index f);
|
||||
// Helper function to count intersections between faces
|
||||
//
|
||||
// Input:
|
||||
// fa index of face A in F
|
||||
// fb index of face B in F
|
||||
inline void count_intersection( const Index fa, const Index fb);
|
||||
// Helper function for box_intersect. Intersect two triangles A and B,
|
||||
// append the intersection object (point,segment,triangle) to a running
|
||||
// list for A and B
|
||||
//
|
||||
// Inputs:
|
||||
// A triangle in 3D
|
||||
// B triangle in 3D
|
||||
// fa index of A in F (and key into offending)
|
||||
// fb index of B in F (and key into offending)
|
||||
// Returns true only if A intersects B
|
||||
//
|
||||
inline bool intersect(
|
||||
const Triangle_3 & A,
|
||||
const Triangle_3 & B,
|
||||
const Index fa,
|
||||
const Index fb);
|
||||
// Helper function for box_intersect. In the case where A and B have
|
||||
// already been identified to share a vertex, then we only want to
|
||||
// add possible segment intersections. Assumes truly duplicate
|
||||
// triangles are not given as input
|
||||
//
|
||||
// Inputs:
|
||||
// A triangle in 3D
|
||||
// B triangle in 3D
|
||||
// fa index of A in F (and key into offending)
|
||||
// fb index of B in F (and key into offending)
|
||||
// va index of shared vertex in A (and key into offending)
|
||||
// vb index of shared vertex in B (and key into offending)
|
||||
// Returns true if intersection (besides shared point)
|
||||
//
|
||||
inline bool single_shared_vertex(
|
||||
const Triangle_3 & A,
|
||||
const Triangle_3 & B,
|
||||
const Index fa,
|
||||
const Index fb,
|
||||
const Index va,
|
||||
const Index vb);
|
||||
// Helper handling one direction
|
||||
inline bool single_shared_vertex(
|
||||
const Triangle_3 & A,
|
||||
const Triangle_3 & B,
|
||||
const Index fa,
|
||||
const Index fb,
|
||||
const Index va);
|
||||
// Helper function for box_intersect. In the case where A and B have
|
||||
// already been identified to share two vertices, then we only want
|
||||
// to add a possible coplanar (Triangle) intersection. Assumes truly
|
||||
// degenerate facets are not givin as input.
|
||||
inline bool double_shared_vertex(
|
||||
const Triangle_3 & A,
|
||||
const Triangle_3 & B,
|
||||
const Index fa,
|
||||
const Index fb,
|
||||
const std::vector<std::pair<Index,Index> > shared);
|
||||
|
||||
public:
|
||||
// Callback function called during box self intersections test. Means
|
||||
// boxes a and b intersect. This method then checks if the triangles
|
||||
// in each box intersect and if so, then processes the intersections
|
||||
//
|
||||
// Inputs:
|
||||
// a box containing a triangle
|
||||
// b box containing a triangle
|
||||
inline void box_intersect(const Box& a, const Box& b);
|
||||
inline void process_intersecting_boxes();
|
||||
public:
|
||||
// Getters:
|
||||
//const IndexList& get_lIF() const{ return lIF;}
|
||||
static inline void box_intersect_static(
|
||||
SelfIntersectMesh * SIM,
|
||||
const Box &a,
|
||||
const Box &b);
|
||||
private:
|
||||
std::mutex m_offending_lock;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation
|
||||
|
||||
#include "mesh_to_cgal_triangle_list.h"
|
||||
#include "remesh_intersections.h"
|
||||
|
||||
#include "../../REDRUM.h"
|
||||
#include "../../get_seconds.h"
|
||||
#include "../../C_STR.h"
|
||||
|
||||
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
// References:
|
||||
// http://minregret.googlecode.com/svn/trunk/skyline/src/extern/CGAL-3.3.1/examples/Polyhedron/polyhedron_self_intersection.cpp
|
||||
// http://www.cgal.org/Manual/3.9/examples/Boolean_set_operations_2/do_intersect.cpp
|
||||
|
||||
// Q: Should we be using CGAL::Polyhedron_3?
|
||||
// A: No! Input is just a list of unoriented triangles. Polyhedron_3 requires
|
||||
// a 2-manifold.
|
||||
// A: But! It seems we could use CGAL::Triangulation_3. Though it won't be easy
|
||||
// to take advantage of functions like insert_in_facet because we want to
|
||||
// constrain segments. Hmmm. Actually Triangulation_3 doesn't look right...
|
||||
|
||||
// CGAL's box_self_intersection_d uses C-style function callbacks without
|
||||
// userdata. This is a leapfrog method for calling a member function. It should
|
||||
// be bound as if the prototype was:
|
||||
// static void box_intersect(const Box &a, const Box &b)
|
||||
// using boost:
|
||||
// boost::function<void(const Box &a,const Box &b)> cb
|
||||
// = boost::bind(&::box_intersect, this, _1,_2);
|
||||
//
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedIF,
|
||||
typename DerivedJ,
|
||||
typename DerivedIM>
|
||||
inline void igl::copyleft::cgal::SelfIntersectMesh<
|
||||
Kernel,
|
||||
DerivedV,
|
||||
DerivedF,
|
||||
DerivedVV,
|
||||
DerivedFF,
|
||||
DerivedIF,
|
||||
DerivedJ,
|
||||
DerivedIM>::box_intersect_static(
|
||||
Self * SIM,
|
||||
const typename Self::Box &a,
|
||||
const typename Self::Box &b)
|
||||
{
|
||||
SIM->box_intersect(a,b);
|
||||
}
|
||||
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedIF,
|
||||
typename DerivedJ,
|
||||
typename DerivedIM>
|
||||
inline igl::copyleft::cgal::SelfIntersectMesh<
|
||||
Kernel,
|
||||
DerivedV,
|
||||
DerivedF,
|
||||
DerivedVV,
|
||||
DerivedFF,
|
||||
DerivedIF,
|
||||
DerivedJ,
|
||||
DerivedIM>::SelfIntersectMesh(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const RemeshSelfIntersectionsParam & params,
|
||||
Eigen::PlainObjectBase<DerivedVV> & VV,
|
||||
Eigen::PlainObjectBase<DerivedFF> & FF,
|
||||
Eigen::PlainObjectBase<DerivedIF> & IF,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J,
|
||||
Eigen::PlainObjectBase<DerivedIM> & IM):
|
||||
V(V),
|
||||
F(F),
|
||||
count(0),
|
||||
T(),
|
||||
lIF(),
|
||||
offending(),
|
||||
params(params)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
|
||||
#ifdef IGL_SELFINTERSECTMESH_DEBUG
|
||||
const auto & tictoc = []() -> double
|
||||
{
|
||||
static double t_start = igl::get_seconds();
|
||||
double diff = igl::get_seconds()-t_start;
|
||||
t_start += diff;
|
||||
return diff;
|
||||
};
|
||||
const auto log_time = [&](const std::string& label) -> void{
|
||||
std::cout << "SelfIntersectMesh." << label << ": "
|
||||
<< tictoc() << std::endl;
|
||||
};
|
||||
tictoc();
|
||||
#endif
|
||||
|
||||
// Compute and process self intersections
|
||||
mesh_to_cgal_triangle_list(V,F,T);
|
||||
#ifdef IGL_SELFINTERSECTMESH_DEBUG
|
||||
log_time("convert_to_triangle_list");
|
||||
#endif
|
||||
// http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Box_intersection_d/Chapter_main.html#Section_63.5
|
||||
// Create the corresponding vector of bounding boxes
|
||||
std::vector<Box> boxes;
|
||||
boxes.reserve(T.size());
|
||||
for (
|
||||
TrianglesIterator tit = T.begin();
|
||||
tit != T.end();
|
||||
++tit)
|
||||
{
|
||||
if (!tit->is_degenerate())
|
||||
{
|
||||
boxes.push_back(Box(tit->bbox(), tit));
|
||||
}
|
||||
}
|
||||
// Leapfrog callback
|
||||
std::function<void(const Box &a,const Box &b)> cb =
|
||||
std::bind(&box_intersect_static, this,
|
||||
// Explicitly use std namespace to avoid confusion with boost (who puts
|
||||
// _1 etc. in global namespace)
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2);
|
||||
#ifdef IGL_SELFINTERSECTMESH_DEBUG
|
||||
log_time("box_and_bind");
|
||||
#endif
|
||||
// Run the self intersection algorithm with all defaults
|
||||
CGAL::box_self_intersection_d(boxes.begin(), boxes.end(),cb);
|
||||
#ifdef IGL_SELFINTERSECTMESH_DEBUG
|
||||
log_time("box_intersection_d");
|
||||
#endif
|
||||
try{
|
||||
process_intersecting_boxes();
|
||||
}catch(int e)
|
||||
{
|
||||
// Rethrow if not IGL_FIRST_HIT_EXCEPTION
|
||||
if(e != IGL_FIRST_HIT_EXCEPTION)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
// Otherwise just fall through
|
||||
}
|
||||
#ifdef IGL_SELFINTERSECTMESH_DEBUG
|
||||
log_time("resolve_intersection");
|
||||
#endif
|
||||
|
||||
// Convert lIF to Eigen matrix
|
||||
assert(lIF.size()%2 == 0);
|
||||
IF.resize(lIF.size()/2,2);
|
||||
{
|
||||
Index i=0;
|
||||
for(
|
||||
typename IndexList::const_iterator ifit = lIF.begin();
|
||||
ifit!=lIF.end();
|
||||
)
|
||||
{
|
||||
IF(i,0) = (*ifit);
|
||||
ifit++;
|
||||
IF(i,1) = (*ifit);
|
||||
ifit++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
#ifdef IGL_SELFINTERSECTMESH_DEBUG
|
||||
log_time("store_intersecting_face_pairs");
|
||||
#endif
|
||||
|
||||
if(params.detect_only)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
remesh_intersections(
|
||||
V,F,T,offending,params.stitch_all,VV,FF,J,IM);
|
||||
|
||||
#ifdef IGL_SELFINTERSECTMESH_DEBUG
|
||||
log_time("remesh_intersection");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedIF,
|
||||
typename DerivedJ,
|
||||
typename DerivedIM>
|
||||
inline void igl::copyleft::cgal::SelfIntersectMesh<
|
||||
Kernel,
|
||||
DerivedV,
|
||||
DerivedF,
|
||||
DerivedVV,
|
||||
DerivedFF,
|
||||
DerivedIF,
|
||||
DerivedJ,
|
||||
DerivedIM>::mark_offensive(const Index f)
|
||||
{
|
||||
using namespace std;
|
||||
lIF.push_back(f);
|
||||
if(offending.count(f) == 0)
|
||||
{
|
||||
// first time marking, initialize with new id and empty list
|
||||
offending[f] = {};
|
||||
}
|
||||
}
|
||||
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedIF,
|
||||
typename DerivedJ,
|
||||
typename DerivedIM>
|
||||
inline void igl::copyleft::cgal::SelfIntersectMesh<
|
||||
Kernel,
|
||||
DerivedV,
|
||||
DerivedF,
|
||||
DerivedVV,
|
||||
DerivedFF,
|
||||
DerivedIF,
|
||||
DerivedJ,
|
||||
DerivedIM>::count_intersection(
|
||||
const Index fa,
|
||||
const Index fb)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(m_offending_lock);
|
||||
mark_offensive(fa);
|
||||
mark_offensive(fb);
|
||||
this->count++;
|
||||
// We found the first intersection
|
||||
if(params.first_only && this->count >= 1)
|
||||
{
|
||||
throw IGL_FIRST_HIT_EXCEPTION;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedIF,
|
||||
typename DerivedJ,
|
||||
typename DerivedIM>
|
||||
inline bool igl::copyleft::cgal::SelfIntersectMesh<
|
||||
Kernel,
|
||||
DerivedV,
|
||||
DerivedF,
|
||||
DerivedVV,
|
||||
DerivedFF,
|
||||
DerivedIF,
|
||||
DerivedJ,
|
||||
DerivedIM>::intersect(
|
||||
const Triangle_3 & A,
|
||||
const Triangle_3 & B,
|
||||
const Index fa,
|
||||
const Index fb)
|
||||
{
|
||||
// Determine whether there is an intersection
|
||||
if(!CGAL::do_intersect(A,B))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
count_intersection(fa,fb);
|
||||
if(!params.detect_only)
|
||||
{
|
||||
// Construct intersection
|
||||
CGAL::Object result = CGAL::intersection(A,B);
|
||||
std::lock_guard<std::mutex> guard(m_offending_lock);
|
||||
offending[fa].push_back({fb, result});
|
||||
offending[fb].push_back({fa, result});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedIF,
|
||||
typename DerivedJ,
|
||||
typename DerivedIM>
|
||||
inline bool igl::copyleft::cgal::SelfIntersectMesh<
|
||||
Kernel,
|
||||
DerivedV,
|
||||
DerivedF,
|
||||
DerivedVV,
|
||||
DerivedFF,
|
||||
DerivedIF,
|
||||
DerivedJ,
|
||||
DerivedIM>::single_shared_vertex(
|
||||
const Triangle_3 & A,
|
||||
const Triangle_3 & B,
|
||||
const Index fa,
|
||||
const Index fb,
|
||||
const Index va,
|
||||
const Index vb)
|
||||
{
|
||||
if(single_shared_vertex(A,B,fa,fb,va))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return single_shared_vertex(B,A,fb,fa,vb);
|
||||
}
|
||||
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedIF,
|
||||
typename DerivedJ,
|
||||
typename DerivedIM>
|
||||
inline bool igl::copyleft::cgal::SelfIntersectMesh<
|
||||
Kernel,
|
||||
DerivedV,
|
||||
DerivedF,
|
||||
DerivedVV,
|
||||
DerivedFF,
|
||||
DerivedIF,
|
||||
DerivedJ,
|
||||
DerivedIM>::single_shared_vertex(
|
||||
const Triangle_3 & A,
|
||||
const Triangle_3 & B,
|
||||
const Index fa,
|
||||
const Index fb,
|
||||
const Index va)
|
||||
{
|
||||
// This was not a good idea. It will not handle coplanar triangles well.
|
||||
using namespace std;
|
||||
Segment_3 sa(
|
||||
A.vertex((va+1)%3),
|
||||
A.vertex((va+2)%3));
|
||||
|
||||
if(CGAL::do_intersect(sa,B))
|
||||
{
|
||||
// can't put count_intersection(fa,fb) here since we use intersect below
|
||||
// and then it will be counted twice.
|
||||
if(params.detect_only)
|
||||
{
|
||||
count_intersection(fa,fb);
|
||||
return true;
|
||||
}
|
||||
CGAL::Object result = CGAL::intersection(sa,B);
|
||||
if(const Point_3 * p = CGAL::object_cast<Point_3 >(&result))
|
||||
{
|
||||
// Single intersection --> segment from shared point to intersection
|
||||
CGAL::Object seg = CGAL::make_object(Segment_3(
|
||||
A.vertex(va),
|
||||
*p));
|
||||
count_intersection(fa,fb);
|
||||
std::lock_guard<std::mutex> guard(m_offending_lock);
|
||||
offending[fa].push_back({fb, seg});
|
||||
offending[fb].push_back({fa, seg});
|
||||
return true;
|
||||
}else if(CGAL::object_cast<Segment_3 >(&result))
|
||||
{
|
||||
// Need to do full test. Intersection could be a general poly.
|
||||
bool test = intersect(A,B,fa,fb);
|
||||
((void)test);
|
||||
assert(test && "intersect should agree with do_intersect");
|
||||
return true;
|
||||
}else
|
||||
{
|
||||
cerr<<REDRUM("Segment ∩ triangle neither point nor segment?")<<endl;
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedIF,
|
||||
typename DerivedJ,
|
||||
typename DerivedIM>
|
||||
inline bool igl::copyleft::cgal::SelfIntersectMesh<
|
||||
Kernel,
|
||||
DerivedV,
|
||||
DerivedF,
|
||||
DerivedVV,
|
||||
DerivedFF,
|
||||
DerivedIF,
|
||||
DerivedJ,
|
||||
DerivedIM>::double_shared_vertex(
|
||||
const Triangle_3 & A,
|
||||
const Triangle_3 & B,
|
||||
const Index fa,
|
||||
const Index fb,
|
||||
const std::vector<std::pair<Index,Index> > shared)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// must be co-planar
|
||||
if(
|
||||
A.supporting_plane() != B.supporting_plane() &&
|
||||
A.supporting_plane() != B.supporting_plane().opposite())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Since A and B are non-degenerate the intersection must be a polygon
|
||||
// (triangle). Either
|
||||
// - the vertex of A (B) opposite the shared edge of lies on B (A), or
|
||||
// - an edge of A intersects and edge of B without sharing a vertex
|
||||
//
|
||||
// Determine if the vertex opposite edge (a0,a1) in triangle A lies in
|
||||
// (intersects) triangle B
|
||||
const auto & opposite_point_inside = [](
|
||||
const Triangle_3 & A, const Index a0, const Index a1, const Triangle_3 & B)
|
||||
-> bool
|
||||
{
|
||||
// get opposite index
|
||||
Index a2 = -1;
|
||||
for(int c = 0;c<3;c++)
|
||||
{
|
||||
if(c != a0 && c != a1)
|
||||
{
|
||||
a2 = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(a2 != -1);
|
||||
bool ret = CGAL::do_intersect(A.vertex(a2),B);
|
||||
return ret;
|
||||
};
|
||||
|
||||
// Determine if edge opposite vertex va in triangle A intersects edge
|
||||
// opposite vertex vb in triangle B.
|
||||
const auto & opposite_edges_intersect = [](
|
||||
const Triangle_3 & A, const Index va,
|
||||
const Triangle_3 & B, const Index vb) -> bool
|
||||
{
|
||||
Segment_3 sa( A.vertex((va+1)%3), A.vertex((va+2)%3));
|
||||
Segment_3 sb( B.vertex((vb+1)%3), B.vertex((vb+2)%3));
|
||||
bool ret = CGAL::do_intersect(sa,sb);
|
||||
return ret;
|
||||
};
|
||||
|
||||
if(
|
||||
!opposite_point_inside(A,shared[0].first,shared[1].first,B) &&
|
||||
!opposite_point_inside(B,shared[0].second,shared[1].second,A) &&
|
||||
!opposite_edges_intersect(A,shared[0].first,B,shared[1].second) &&
|
||||
!opposite_edges_intersect(A,shared[1].first,B,shared[0].second))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// there is an intersection indeed
|
||||
count_intersection(fa,fb);
|
||||
if(params.detect_only)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// Construct intersection
|
||||
try
|
||||
{
|
||||
// This can fail for Epick but not Epeck
|
||||
CGAL::Object result = CGAL::intersection(A,B);
|
||||
if(!result.empty())
|
||||
{
|
||||
if(CGAL::object_cast<Segment_3 >(&result))
|
||||
{
|
||||
// not coplanar
|
||||
assert(false &&
|
||||
"Co-planar non-degenerate triangles should intersect over triangle");
|
||||
return false;
|
||||
} else if(CGAL::object_cast<Point_3 >(&result))
|
||||
{
|
||||
// this "shouldn't" happen but does for inexact
|
||||
assert(false &&
|
||||
"Co-planar non-degenerate triangles should intersect over triangle");
|
||||
return false;
|
||||
} else
|
||||
{
|
||||
// Triangle object
|
||||
std::lock_guard<std::mutex> guard(m_offending_lock);
|
||||
offending[fa].push_back({fb, result});
|
||||
offending[fb].push_back({fa, result});
|
||||
return true;
|
||||
}
|
||||
}else
|
||||
{
|
||||
// CGAL::intersection is disagreeing with do_intersect
|
||||
assert(false && "CGAL::intersection should agree with predicate tests");
|
||||
return false;
|
||||
}
|
||||
}catch(...)
|
||||
{
|
||||
// This catches some cgal assertion:
|
||||
// CGAL error: assertion violation!
|
||||
// Expression : is_finite(d)
|
||||
// File : /opt/local/include/CGAL/GMP/Gmpq_type.h
|
||||
// Line : 132
|
||||
// Explanation:
|
||||
// But only if NDEBUG is not defined, otherwise there's an uncaught
|
||||
// "Floating point exception: 8" SIGFPE
|
||||
return false;
|
||||
}
|
||||
// No intersection.
|
||||
return false;
|
||||
}
|
||||
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedIF,
|
||||
typename DerivedJ,
|
||||
typename DerivedIM>
|
||||
inline void igl::copyleft::cgal::SelfIntersectMesh<
|
||||
Kernel,
|
||||
DerivedV,
|
||||
DerivedF,
|
||||
DerivedVV,
|
||||
DerivedFF,
|
||||
DerivedIF,
|
||||
DerivedJ,
|
||||
DerivedIM>::box_intersect(
|
||||
const Box& a,
|
||||
const Box& b)
|
||||
{
|
||||
candidate_triangle_pairs.push_back({a.handle(), b.handle()});
|
||||
}
|
||||
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename DerivedIF,
|
||||
typename DerivedJ,
|
||||
typename DerivedIM>
|
||||
inline void igl::copyleft::cgal::SelfIntersectMesh<
|
||||
Kernel,
|
||||
DerivedV,
|
||||
DerivedF,
|
||||
DerivedVV,
|
||||
DerivedFF,
|
||||
DerivedIF,
|
||||
DerivedJ,
|
||||
DerivedIM>::process_intersecting_boxes()
|
||||
{
|
||||
std::vector<std::mutex> triangle_locks(T.size());
|
||||
std::vector<std::mutex> vertex_locks(V.rows());
|
||||
std::mutex index_lock;
|
||||
std::mutex exception_mutex;
|
||||
bool exception_fired = false;
|
||||
int exception = -1;
|
||||
auto process_chunk =
|
||||
[&](
|
||||
const size_t first,
|
||||
const size_t last) -> void
|
||||
{
|
||||
try
|
||||
{
|
||||
assert(last >= first);
|
||||
|
||||
for (size_t i=first; i<last; i++)
|
||||
{
|
||||
if(exception_fired) return;
|
||||
Index fa=T.size(), fb=T.size();
|
||||
{
|
||||
// Before knowing which triangles are involved, we need to lock
|
||||
// everything to prevent race condition in updating reference
|
||||
// counters.
|
||||
std::lock_guard<std::mutex> guard(index_lock);
|
||||
const auto& tri_pair = candidate_triangle_pairs[i];
|
||||
fa = tri_pair.first - T.begin();
|
||||
fb = tri_pair.second - T.begin();
|
||||
}
|
||||
assert(fa < T.size());
|
||||
assert(fb < T.size());
|
||||
|
||||
// Lock triangles
|
||||
std::lock_guard<std::mutex> guard_A(triangle_locks[fa]);
|
||||
std::lock_guard<std::mutex> guard_B(triangle_locks[fb]);
|
||||
|
||||
// Lock vertices
|
||||
std::list<std::lock_guard<std::mutex> > guard_vertices;
|
||||
{
|
||||
std::vector<typename DerivedF::Scalar> unique_vertices;
|
||||
std::vector<size_t> tmp1, tmp2;
|
||||
igl::unique({F(fa,0), F(fa,1), F(fa,2), F(fb,0), F(fb,1), F(fb,2)},
|
||||
unique_vertices, tmp1, tmp2);
|
||||
std::for_each(unique_vertices.begin(), unique_vertices.end(),
|
||||
[&](const typename DerivedF::Scalar& vi) {
|
||||
guard_vertices.emplace_back(vertex_locks[vi]);
|
||||
});
|
||||
}
|
||||
if(exception_fired) return;
|
||||
|
||||
const Triangle_3& A = T[fa];
|
||||
const Triangle_3& B = T[fb];
|
||||
|
||||
// Number of combinatorially shared vertices
|
||||
Index comb_shared_vertices = 0;
|
||||
// Number of geometrically shared vertices (*not* including
|
||||
// combinatorially shared)
|
||||
Index geo_shared_vertices = 0;
|
||||
// Keep track of shared vertex indices
|
||||
std::vector<std::pair<Index,Index> > shared;
|
||||
Index ea,eb;
|
||||
for(ea=0;ea<3;ea++)
|
||||
{
|
||||
for(eb=0;eb<3;eb++)
|
||||
{
|
||||
if(F(fa,ea) == F(fb,eb))
|
||||
{
|
||||
comb_shared_vertices++;
|
||||
shared.emplace_back(ea,eb);
|
||||
}else if(A.vertex(ea) == B.vertex(eb))
|
||||
{
|
||||
geo_shared_vertices++;
|
||||
shared.emplace_back(ea,eb);
|
||||
}
|
||||
}
|
||||
}
|
||||
const Index total_shared_vertices =
|
||||
comb_shared_vertices + geo_shared_vertices;
|
||||
if(exception_fired) return;
|
||||
|
||||
if(comb_shared_vertices== 3)
|
||||
{
|
||||
assert(shared.size() == 3);
|
||||
// Combinatorially duplicate face, these should be removed by
|
||||
// preprocessing
|
||||
continue;
|
||||
}
|
||||
if(total_shared_vertices== 3)
|
||||
{
|
||||
assert(shared.size() == 3);
|
||||
// Geometrically duplicate face, these should be removed by
|
||||
// preprocessing
|
||||
continue;
|
||||
}
|
||||
if(total_shared_vertices == 2)
|
||||
{
|
||||
assert(shared.size() == 2);
|
||||
// Q: What about coplanar?
|
||||
//
|
||||
// o o
|
||||
// |\ /|
|
||||
// | \/ |
|
||||
// | /\ |
|
||||
// |/ \|
|
||||
// o----o
|
||||
double_shared_vertex(A,B,fa,fb,shared);
|
||||
continue;
|
||||
}
|
||||
assert(total_shared_vertices<=1);
|
||||
if(total_shared_vertices==1)
|
||||
{
|
||||
single_shared_vertex(A,B,fa,fb,shared[0].first,shared[0].second);
|
||||
}else
|
||||
{
|
||||
intersect(A,B,fa,fb);
|
||||
}
|
||||
}
|
||||
}catch(int e)
|
||||
{
|
||||
std::lock_guard<std::mutex> exception_lock(exception_mutex);
|
||||
exception_fired = true;
|
||||
exception = e;
|
||||
}
|
||||
};
|
||||
size_t num_threads=0;
|
||||
const size_t hardware_limit = std::thread::hardware_concurrency();
|
||||
if (const char* igl_num_threads = std::getenv("LIBIGL_NUM_THREADS")) {
|
||||
num_threads = atoi(igl_num_threads);
|
||||
}
|
||||
if (num_threads == 0 || num_threads > hardware_limit) {
|
||||
num_threads = hardware_limit;
|
||||
}
|
||||
assert(num_threads > 0);
|
||||
const size_t num_pairs = candidate_triangle_pairs.size();
|
||||
const size_t chunk_size = num_pairs / num_threads;
|
||||
std::vector<std::thread> threads;
|
||||
for (size_t i=0; i<num_threads-1; i++)
|
||||
{
|
||||
threads.emplace_back(process_chunk, i*chunk_size, (i+1)*chunk_size);
|
||||
}
|
||||
// Do some work in the master thread.
|
||||
process_chunk((num_threads-1)*chunk_size, num_pairs);
|
||||
for (auto& t : threads)
|
||||
{
|
||||
if (t.joinable()) t.join();
|
||||
}
|
||||
if(exception_fired) throw exception;
|
||||
//process_chunk(0, candidate_triangle_pairs.size());
|
||||
}
|
||||
|
||||
#endif
|
||||
80
src/libigl/igl/copyleft/cgal/assign.cpp
Normal file
80
src/libigl/igl/copyleft/cgal/assign.cpp
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "assign.h"
|
||||
#include "assign_scalar.h"
|
||||
|
||||
template <typename DerivedC, typename DerivedD>
|
||||
IGL_INLINE void igl::copyleft::cgal::assign(
|
||||
const Eigen::MatrixBase<DerivedC> & C,
|
||||
Eigen::PlainObjectBase<DerivedD> & D)
|
||||
{
|
||||
D.resizeLike(C);
|
||||
for(int i = 0;i<C.rows();i++)
|
||||
{
|
||||
for(int j = 0;j<C.cols();j++)
|
||||
{
|
||||
assign_scalar(C(i,j),D(i,j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ReturnScalar, typename DerivedC>
|
||||
IGL_INLINE
|
||||
Eigen::Matrix<
|
||||
ReturnScalar,
|
||||
DerivedC::RowsAtCompileTime,
|
||||
DerivedC::ColsAtCompileTime,
|
||||
1,
|
||||
DerivedC::MaxRowsAtCompileTime,
|
||||
DerivedC::MaxColsAtCompileTime>
|
||||
igl::copyleft::cgal::assign(
|
||||
const Eigen::MatrixBase<DerivedC> & C)
|
||||
{
|
||||
Eigen::Matrix<
|
||||
ReturnScalar,
|
||||
DerivedC::RowsAtCompileTime,
|
||||
DerivedC::ColsAtCompileTime,
|
||||
1,
|
||||
DerivedC::MaxRowsAtCompileTime,
|
||||
DerivedC::MaxColsAtCompileTime> D;
|
||||
assign(C,D);
|
||||
return D;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> >&);
|
||||
template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<double, 8, 3, 0, 8, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 8, 3, 0, 8, 3> >&);
|
||||
#endif
|
||||
42
src/libigl/igl/copyleft/cgal/assign.h
Normal file
42
src/libigl/igl/copyleft/cgal/assign.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_ASSIGN_H
|
||||
#define IGL_COPYLEFT_CGAL_ASSIGN_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
template <typename DerivedC, typename DerivedD>
|
||||
IGL_INLINE void assign(
|
||||
const Eigen::MatrixBase<DerivedC> & C,
|
||||
Eigen::PlainObjectBase<DerivedD> & D);
|
||||
template <typename ReturnScalar, typename DerivedC>
|
||||
IGL_INLINE
|
||||
Eigen::Matrix<
|
||||
ReturnScalar,
|
||||
DerivedC::RowsAtCompileTime,
|
||||
DerivedC::ColsAtCompileTime,
|
||||
1,
|
||||
DerivedC::MaxRowsAtCompileTime,
|
||||
DerivedC::MaxColsAtCompileTime>
|
||||
assign(
|
||||
const Eigen::MatrixBase<DerivedC> & C);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "assign.cpp"
|
||||
#endif
|
||||
#endif
|
||||
136
src/libigl/igl/copyleft/cgal/assign_scalar.cpp
Normal file
136
src/libigl/igl/copyleft/cgal/assign_scalar.cpp
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "assign_scalar.h"
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const CGAL::Epeck::FT & cgal,
|
||||
CGAL::Epeck::FT & d)
|
||||
{
|
||||
d = cgal;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const CGAL::Epeck::FT & _cgal,
|
||||
double & d)
|
||||
{
|
||||
// FORCE evaluation of the exact type otherwise interval might be huge.
|
||||
const CGAL::Epeck::FT cgal = _cgal.exact();
|
||||
const auto interval = CGAL::to_interval(cgal);
|
||||
d = interval.first;
|
||||
do {
|
||||
const double next = nextafter(d, interval.second);
|
||||
if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break;
|
||||
d = next;
|
||||
} while (d < interval.second);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const CGAL::Epeck::FT & _cgal,
|
||||
float& d)
|
||||
{
|
||||
// FORCE evaluation of the exact type otherwise interval might be huge.
|
||||
const CGAL::Epeck::FT cgal = _cgal.exact();
|
||||
const auto interval = CGAL::to_interval(cgal);
|
||||
d = interval.first;
|
||||
do {
|
||||
const float next = nextafter(d, float(interval.second));
|
||||
if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break;
|
||||
d = next;
|
||||
} while (d < float(interval.second));
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const double & c,
|
||||
double & d)
|
||||
{
|
||||
d = c;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const float& c,
|
||||
float& d)
|
||||
{
|
||||
d = c;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const float& c,
|
||||
double& d)
|
||||
{
|
||||
d = c;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
|
||||
CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & d)
|
||||
{
|
||||
d = cgal;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
|
||||
double & d)
|
||||
{
|
||||
const auto interval = CGAL::to_interval(cgal);
|
||||
d = interval.first;
|
||||
do {
|
||||
const double next = nextafter(d, interval.second);
|
||||
if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break;
|
||||
d = next;
|
||||
} while (d < interval.second);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
|
||||
float& d)
|
||||
{
|
||||
const auto interval = CGAL::to_interval(cgal);
|
||||
d = interval.first;
|
||||
do {
|
||||
const float next = nextafter(d, float(interval.second));
|
||||
if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break;
|
||||
d = next;
|
||||
} while (d < float(interval.second));
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
|
||||
CGAL::Simple_cartesian<mpq_class>::FT & d)
|
||||
{
|
||||
d = cgal;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
|
||||
double & d)
|
||||
{
|
||||
const auto interval = CGAL::to_interval(cgal);
|
||||
d = interval.first;
|
||||
do {
|
||||
const double next = nextafter(d, interval.second);
|
||||
if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break;
|
||||
d = next;
|
||||
} while (d < interval.second);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::assign_scalar(
|
||||
const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
|
||||
float& d)
|
||||
{
|
||||
const auto interval = CGAL::to_interval(cgal);
|
||||
d = interval.first;
|
||||
do {
|
||||
const float next = nextafter(d, float(interval.second));
|
||||
if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break;
|
||||
d = next;
|
||||
} while (d < float(interval.second));
|
||||
}
|
||||
|
||||
#endif // WIN32
|
||||
74
src/libigl/igl/copyleft/cgal/assign_scalar.h
Normal file
74
src/libigl/igl/copyleft/cgal/assign_scalar.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_ASSIGN_SCALAR_H
|
||||
#define IGL_COPYLEFT_CGAL_ASSIGN_SCALAR_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel_with_sqrt.h>
|
||||
#ifndef WIN32
|
||||
#include <CGAL/gmpxx.h>
|
||||
#endif
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Inputs:
|
||||
// cgal cgal scalar
|
||||
// Outputs:
|
||||
// d output scalar
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Epeck::FT & cgal,
|
||||
CGAL::Epeck::FT & d);
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Epeck::FT & cgal,
|
||||
double & d);
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Epeck::FT & cgal,
|
||||
float& d);
|
||||
IGL_INLINE void assign_scalar(
|
||||
const double & c,
|
||||
double & d);
|
||||
IGL_INLINE void assign_scalar(
|
||||
const float& c,
|
||||
float & d);
|
||||
IGL_INLINE void assign_scalar(
|
||||
const float& c,
|
||||
double& d);
|
||||
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
|
||||
CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & d);
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
|
||||
double & d);
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
|
||||
float& d);
|
||||
|
||||
#ifndef WIN32
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
|
||||
CGAL::Simple_cartesian<mpq_class>::FT & d);
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
|
||||
double & d);
|
||||
IGL_INLINE void assign_scalar(
|
||||
const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
|
||||
float& d);
|
||||
#endif // WIN32
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "assign_scalar.cpp"
|
||||
#endif
|
||||
#endif
|
||||
15
src/libigl/igl/copyleft/cgal/barycenter.cpp
Normal file
15
src/libigl/igl/copyleft/cgal/barycenter.cpp
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "../../barycenter.h"
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
#undef IGL_STATIC_LIBRARY
|
||||
#include "../../barycenter.cpp"
|
||||
template void igl::barycenter<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
34
src/libigl/igl/copyleft/cgal/cell_adjacency.cpp
Normal file
34
src/libigl/igl/copyleft/cgal/cell_adjacency.cpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
|
||||
#include "cell_adjacency.h"
|
||||
|
||||
template <typename DerivedC>
|
||||
IGL_INLINE void igl::copyleft::cgal::cell_adjacency(
|
||||
const Eigen::PlainObjectBase<DerivedC>& per_patch_cells,
|
||||
const size_t num_cells,
|
||||
std::vector<std::set<std::tuple<typename DerivedC::Scalar, bool, size_t> > >&
|
||||
adjacency_list) {
|
||||
|
||||
const size_t num_patches = per_patch_cells.rows();
|
||||
adjacency_list.resize(num_cells);
|
||||
for (size_t i=0; i<num_patches; i++) {
|
||||
const int positive_cell = per_patch_cells(i,0);
|
||||
const int negative_cell = per_patch_cells(i,1);
|
||||
adjacency_list[positive_cell].emplace(negative_cell, false, i);
|
||||
adjacency_list[negative_cell].emplace(positive_cell, true, i);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
template void igl::copyleft::cgal::cell_adjacency<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, unsigned long, std::vector<std::set<std::tuple<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, bool, unsigned long>, std::less<std::tuple<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, bool, unsigned long> >, std::allocator<std::tuple<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, bool, unsigned long> > >, std::allocator<std::set<std::tuple<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, bool, unsigned long>, std::less<std::tuple<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, bool, unsigned long> >, std::allocator<std::tuple<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, bool, unsigned long> > > > >&);
|
||||
#ifdef WIN32
|
||||
template void igl::copyleft::cgal::cell_adjacency<class Eigen::Matrix<int, -1, -1, 0, -1, -1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, unsigned __int64, class std::vector<class std::set<class std::tuple<int, bool, unsigned __int64>, struct std::less<class std::tuple<int, bool, unsigned __int64>>, class std::allocator<class std::tuple<int, bool, unsigned __int64>>>, class std::allocator<class std::set<class std::tuple<int, bool, unsigned __int64>, struct std::less<class std::tuple<int, bool, unsigned __int64>>, class std::allocator<class std::tuple<int, bool, unsigned __int64>>>>> &);
|
||||
#endif
|
||||
#endif
|
||||
50
src/libigl/igl/copyleft/cgal/cell_adjacency.h
Normal file
50
src/libigl/igl/copyleft/cgal/cell_adjacency.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
#ifndef IGL_COPYLEFT_CGAL_CELL_ADJACENCY_H
|
||||
#define IGL_COPYLEFT_CGAL_CELL_ADJACENCY_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <set>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Inputs:
|
||||
// per_patch_cells #P by 2 list of cell labels on each side of each
|
||||
// patch. Cell labels are assumed to be continuous
|
||||
// from 0 to #C.
|
||||
// num_cells number of cells.
|
||||
//
|
||||
// Outputs:
|
||||
// adjacency_list #C array of list of adjcent cell information. If
|
||||
// cell i and cell j are adjacent via patch x, where i
|
||||
// is on the positive side of x, and j is on the
|
||||
// negative side. Then,
|
||||
// adjacency_list[i] will contain the entry {j, false, x}
|
||||
// and
|
||||
// adjacency_list[j] will contain the entry {i, true, x}
|
||||
template < typename DerivedC >
|
||||
IGL_INLINE void cell_adjacency(
|
||||
const Eigen::PlainObjectBase<DerivedC>& per_patch_cells,
|
||||
const size_t num_cells,
|
||||
std::vector<std::set<std::tuple<typename DerivedC::Scalar, bool, size_t> > >&
|
||||
adjacency_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "cell_adjacency.cpp"
|
||||
#endif
|
||||
#endif
|
||||
504
src/libigl/igl/copyleft/cgal/closest_facet.cpp
Normal file
504
src/libigl/igl/copyleft/cgal/closest_facet.cpp
Normal file
|
|
@ -0,0 +1,504 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
#include "closest_facet.h"
|
||||
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "order_facets_around_edge.h"
|
||||
#include "submesh_aabb_tree.h"
|
||||
#include "../../vertex_triangle_adjacency.h"
|
||||
#include "../../LinSpaced.h"
|
||||
//#include "../../writePLY.h"
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename DerivedP,
|
||||
typename uE2EType,
|
||||
typename DerivedEMAP,
|
||||
typename DerivedR,
|
||||
typename DerivedS >
|
||||
IGL_INLINE void igl::copyleft::cgal::closest_facet(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
Eigen::PlainObjectBase<DerivedR>& R,
|
||||
Eigen::PlainObjectBase<DerivedS>& S)
|
||||
{
|
||||
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
|
||||
typedef Kernel::Point_3 Point_3;
|
||||
typedef Kernel::Plane_3 Plane_3;
|
||||
typedef Kernel::Segment_3 Segment_3;
|
||||
typedef Kernel::Triangle_3 Triangle;
|
||||
typedef std::vector<Triangle>::iterator Iterator;
|
||||
typedef CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
|
||||
typedef CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
|
||||
typedef CGAL::AABB_tree<AABB_triangle_traits> Tree;
|
||||
|
||||
if (F.rows() <= 0 || I.rows() <= 0) {
|
||||
throw std::runtime_error(
|
||||
"Closest facet cannot be computed on empty mesh.");
|
||||
}
|
||||
|
||||
std::vector<std::vector<size_t> > VF, VFi;
|
||||
igl::vertex_triangle_adjacency(V.rows(), F, VF, VFi);
|
||||
std::vector<bool> in_I;
|
||||
std::vector<Triangle> triangles;
|
||||
Tree tree;
|
||||
submesh_aabb_tree(V,F,I,tree,triangles,in_I);
|
||||
|
||||
return closest_facet(
|
||||
V,F,I,P,uE2E,EMAP,VF,VFi,tree,triangles,in_I,R,S);
|
||||
}
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename DerivedP,
|
||||
typename uE2EType,
|
||||
typename DerivedEMAP,
|
||||
typename Kernel,
|
||||
typename DerivedR,
|
||||
typename DerivedS >
|
||||
IGL_INLINE void igl::copyleft::cgal::closest_facet(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
const std::vector<std::vector<size_t> > & VF,
|
||||
const std::vector<std::vector<size_t> > & VFi,
|
||||
const CGAL::AABB_tree<
|
||||
CGAL::AABB_traits<
|
||||
Kernel,
|
||||
CGAL::AABB_triangle_primitive<
|
||||
Kernel, typename std::vector<
|
||||
typename Kernel::Triangle_3 >::iterator > > > & tree,
|
||||
const std::vector<typename Kernel::Triangle_3 > & triangles,
|
||||
const std::vector<bool> & in_I,
|
||||
Eigen::PlainObjectBase<DerivedR>& R,
|
||||
Eigen::PlainObjectBase<DerivedS>& S)
|
||||
{
|
||||
typedef typename Kernel::Point_3 Point_3;
|
||||
typedef typename Kernel::Plane_3 Plane_3;
|
||||
typedef typename Kernel::Segment_3 Segment_3;
|
||||
typedef typename Kernel::Triangle_3 Triangle;
|
||||
typedef typename std::vector<Triangle>::iterator Iterator;
|
||||
typedef typename CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
|
||||
typedef typename CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
|
||||
typedef typename CGAL::AABB_tree<AABB_triangle_traits> Tree;
|
||||
|
||||
const size_t num_faces = I.rows();
|
||||
if (F.rows() <= 0 || I.rows() <= 0) {
|
||||
throw std::runtime_error(
|
||||
"Closest facet cannot be computed on empty mesh.");
|
||||
}
|
||||
|
||||
auto on_the_positive_side = [&](size_t fid, const Point_3& p) -> bool
|
||||
{
|
||||
const auto& f = F.row(fid).eval();
|
||||
Point_3 v0(V(f[0], 0), V(f[0], 1), V(f[0], 2));
|
||||
Point_3 v1(V(f[1], 0), V(f[1], 1), V(f[1], 2));
|
||||
Point_3 v2(V(f[2], 0), V(f[2], 1), V(f[2], 2));
|
||||
auto ori = CGAL::orientation(v0, v1, v2, p);
|
||||
switch (ori) {
|
||||
case CGAL::POSITIVE:
|
||||
return true;
|
||||
case CGAL::NEGATIVE:
|
||||
return false;
|
||||
case CGAL::COPLANAR:
|
||||
// Warning:
|
||||
// This can only happen if fid contains a boundary edge.
|
||||
// Categorized this ambiguous case as negative side.
|
||||
return false;
|
||||
default:
|
||||
throw std::runtime_error("Unknown CGAL state.");
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
auto get_orientation = [&](size_t fid, size_t s, size_t d) -> bool
|
||||
{
|
||||
const auto& f = F.row(fid);
|
||||
if ((size_t)f[0] == s && (size_t)f[1] == d) return false;
|
||||
else if ((size_t)f[1] == s && (size_t)f[2] == d) return false;
|
||||
else if ((size_t)f[2] == s && (size_t)f[0] == d) return false;
|
||||
else if ((size_t)f[0] == d && (size_t)f[1] == s) return true;
|
||||
else if ((size_t)f[1] == d && (size_t)f[2] == s) return true;
|
||||
else if ((size_t)f[2] == d && (size_t)f[0] == s) return true;
|
||||
else {
|
||||
throw std::runtime_error(
|
||||
"Cannot compute orientation due to incorrect connectivity");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
auto index_to_signed_index = [&](size_t index, bool ori) -> int{
|
||||
return (index+1) * (ori? 1:-1);
|
||||
};
|
||||
//auto signed_index_to_index = [&](int signed_index) -> size_t {
|
||||
// return abs(signed_index) - 1;
|
||||
//};
|
||||
|
||||
enum ElementType { VERTEX, EDGE, FACE };
|
||||
auto determine_element_type = [&](const Point_3& p, const size_t fid,
|
||||
size_t& element_index) -> ElementType {
|
||||
const auto& tri = triangles[fid];
|
||||
const Point_3 p0 = tri[0];
|
||||
const Point_3 p1 = tri[1];
|
||||
const Point_3 p2 = tri[2];
|
||||
|
||||
if (p == p0) { element_index = 0; return VERTEX; }
|
||||
if (p == p1) { element_index = 1; return VERTEX; }
|
||||
if (p == p2) { element_index = 2; return VERTEX; }
|
||||
if (CGAL::collinear(p0, p1, p)) { element_index = 2; return EDGE; }
|
||||
if (CGAL::collinear(p1, p2, p)) { element_index = 0; return EDGE; }
|
||||
if (CGAL::collinear(p2, p0, p)) { element_index = 1; return EDGE; }
|
||||
|
||||
element_index = 0;
|
||||
return FACE;
|
||||
};
|
||||
|
||||
auto process_edge_case = [&](
|
||||
size_t query_idx,
|
||||
const size_t s, const size_t d,
|
||||
size_t preferred_facet,
|
||||
bool& orientation) -> size_t
|
||||
{
|
||||
Point_3 query_point(
|
||||
P(query_idx, 0),
|
||||
P(query_idx, 1),
|
||||
P(query_idx, 2));
|
||||
|
||||
size_t corner_idx = std::numeric_limits<size_t>::max();
|
||||
if ((s == F(preferred_facet, 0) && d == F(preferred_facet, 1)) ||
|
||||
(s == F(preferred_facet, 1) && d == F(preferred_facet, 0)))
|
||||
{
|
||||
corner_idx = 2;
|
||||
} else if ((s == F(preferred_facet, 0) && d == F(preferred_facet, 2)) ||
|
||||
(s == F(preferred_facet, 2) && d == F(preferred_facet, 0)))
|
||||
{
|
||||
corner_idx = 1;
|
||||
} else if ((s == F(preferred_facet, 1) && d == F(preferred_facet, 2)) ||
|
||||
(s == F(preferred_facet, 2) && d == F(preferred_facet, 1)))
|
||||
{
|
||||
corner_idx = 0;
|
||||
} else
|
||||
{
|
||||
std::cerr << "s: " << s << "\t d:" << d << std::endl;
|
||||
std::cerr << F.row(preferred_facet) << std::endl;
|
||||
throw std::runtime_error(
|
||||
"Invalid connectivity, edge does not belong to facet");
|
||||
}
|
||||
|
||||
auto ueid = EMAP(preferred_facet + corner_idx * F.rows());
|
||||
auto eids = uE2E[ueid];
|
||||
std::vector<size_t> intersected_face_indices;
|
||||
for (auto eid : eids)
|
||||
{
|
||||
const size_t fid = eid % F.rows();
|
||||
if (in_I[fid])
|
||||
{
|
||||
intersected_face_indices.push_back(fid);
|
||||
}
|
||||
}
|
||||
|
||||
const size_t num_intersected_faces = intersected_face_indices.size();
|
||||
std::vector<int> intersected_face_signed_indices(num_intersected_faces);
|
||||
std::transform(
|
||||
intersected_face_indices.begin(),
|
||||
intersected_face_indices.end(),
|
||||
intersected_face_signed_indices.begin(),
|
||||
[&](size_t index) {
|
||||
return index_to_signed_index(
|
||||
index, get_orientation(index, s,d));
|
||||
});
|
||||
|
||||
assert(num_intersected_faces >= 1);
|
||||
if (num_intersected_faces == 1)
|
||||
{
|
||||
// The edge must be a boundary edge. Thus, the orientation can be
|
||||
// simply determined by checking if the query point is on the
|
||||
// positive side of the facet.
|
||||
const size_t fid = intersected_face_indices[0];
|
||||
orientation = on_the_positive_side(fid, query_point);
|
||||
return fid;
|
||||
}
|
||||
|
||||
Eigen::VectorXi order;
|
||||
DerivedP pivot = P.row(query_idx).eval();
|
||||
igl::copyleft::cgal::order_facets_around_edge(V, F, s, d,
|
||||
intersected_face_signed_indices,
|
||||
pivot, order);
|
||||
|
||||
// Although first and last are equivalent, make the choice based on
|
||||
// preferred_facet.
|
||||
const size_t first = order[0];
|
||||
const size_t last = order[num_intersected_faces-1];
|
||||
if (intersected_face_indices[first] == preferred_facet) {
|
||||
orientation = intersected_face_signed_indices[first] < 0;
|
||||
return intersected_face_indices[first];
|
||||
} else if (intersected_face_indices[last] == preferred_facet) {
|
||||
orientation = intersected_face_signed_indices[last] > 0;
|
||||
return intersected_face_indices[last];
|
||||
} else {
|
||||
orientation = intersected_face_signed_indices[order[0]] < 0;
|
||||
return intersected_face_indices[order[0]];
|
||||
}
|
||||
};
|
||||
|
||||
auto process_face_case = [&](
|
||||
const size_t query_idx, const Point_3& closest_point,
|
||||
const size_t fid, bool& orientation) -> size_t {
|
||||
const auto& f = F.row(I(fid, 0));
|
||||
return process_edge_case(query_idx, f[0], f[1], I(fid, 0), orientation);
|
||||
};
|
||||
|
||||
// Given that the closest point to query point P(query_idx,:) on (V,F(I,:))
|
||||
// is the vertex at V(s,:) which is incident at least on triangle
|
||||
// F(preferred_facet,:), determine a facet incident on V(s,:) that is
|
||||
// _exposed_ to the query point and determine whether that facet is facing
|
||||
// _toward_ or _away_ from the query point.
|
||||
//
|
||||
// Inputs:
|
||||
// query_idx index into P of query point
|
||||
// s index into V of closest point at vertex
|
||||
// preferred_facet facet incident on s
|
||||
// Outputs:
|
||||
// orientation whether returned face is facing toward or away from
|
||||
// query (parity unclear)
|
||||
// Returns face guaranteed to be "exposed" to P(query_idx,:)
|
||||
auto process_vertex_case = [&](
|
||||
const size_t query_idx,
|
||||
size_t s,
|
||||
size_t preferred_facet,
|
||||
bool& orientation) -> size_t
|
||||
{
|
||||
const Point_3 query_point(
|
||||
P(query_idx, 0), P(query_idx, 1), P(query_idx, 2));
|
||||
const Point_3 closest_point(V(s, 0), V(s, 1), V(s, 2));
|
||||
std::vector<size_t> adj_faces;
|
||||
std::vector<size_t> adj_face_corners;
|
||||
{
|
||||
// Gather adj faces to s within I.
|
||||
const auto& all_adj_faces = VF[s];
|
||||
const auto& all_adj_face_corners = VFi[s];
|
||||
const size_t num_all_adj_faces = all_adj_faces.size();
|
||||
for (size_t i=0; i<num_all_adj_faces; i++)
|
||||
{
|
||||
const size_t fid = all_adj_faces[i];
|
||||
// Shouldn't this always be true if I is a full connected component?
|
||||
if (in_I[fid])
|
||||
{
|
||||
adj_faces.push_back(fid);
|
||||
adj_face_corners.push_back(all_adj_face_corners[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
const size_t num_adj_faces = adj_faces.size();
|
||||
assert(num_adj_faces > 0);
|
||||
|
||||
std::set<size_t> adj_vertices_set;
|
||||
std::unordered_multimap<size_t, size_t> v2f;
|
||||
for (size_t i=0; i<num_adj_faces; i++)
|
||||
{
|
||||
const size_t fid = adj_faces[i];
|
||||
const size_t cid = adj_face_corners[i];
|
||||
const auto& f = F.row(adj_faces[i]);
|
||||
const size_t next = f[(cid+1)%3];
|
||||
const size_t prev = f[(cid+2)%3];
|
||||
adj_vertices_set.insert(next);
|
||||
adj_vertices_set.insert(prev);
|
||||
v2f.insert({{next, fid}, {prev, fid}});
|
||||
}
|
||||
const size_t num_adj_vertices = adj_vertices_set.size();
|
||||
std::vector<size_t> adj_vertices(num_adj_vertices);
|
||||
std::copy(adj_vertices_set.begin(), adj_vertices_set.end(),
|
||||
adj_vertices.begin());
|
||||
|
||||
std::vector<Point_3> adj_points;
|
||||
for (size_t vid : adj_vertices)
|
||||
{
|
||||
adj_points.emplace_back(V(vid,0), V(vid,1), V(vid,2));
|
||||
}
|
||||
|
||||
// A plane is on the exterior if all adj_points lies on or to
|
||||
// one side of the plane.
|
||||
auto is_on_exterior = [&](const Plane_3& separator) -> bool{
|
||||
size_t positive=0;
|
||||
size_t negative=0;
|
||||
size_t coplanar=0;
|
||||
for (const auto& point : adj_points) {
|
||||
switch(separator.oriented_side(point)) {
|
||||
case CGAL::ON_POSITIVE_SIDE:
|
||||
positive++;
|
||||
break;
|
||||
case CGAL::ON_NEGATIVE_SIDE:
|
||||
negative++;
|
||||
break;
|
||||
case CGAL::ON_ORIENTED_BOUNDARY:
|
||||
coplanar++;
|
||||
break;
|
||||
default:
|
||||
throw "Unknown plane-point orientation";
|
||||
}
|
||||
}
|
||||
auto query_orientation = separator.oriented_side(query_point);
|
||||
if (query_orientation == CGAL::ON_ORIENTED_BOUNDARY &&
|
||||
(positive == 0 && negative == 0)) {
|
||||
// All adj vertices and query point are coplanar.
|
||||
// In this case, all separators are equally valid.
|
||||
return true;
|
||||
} else {
|
||||
bool r = (positive == 0 && query_orientation == CGAL::POSITIVE)
|
||||
|| (negative == 0 && query_orientation == CGAL::NEGATIVE);
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
size_t d = std::numeric_limits<size_t>::max();
|
||||
for (size_t i=0; i<num_adj_vertices; i++) {
|
||||
const size_t vi = adj_vertices[i];
|
||||
for (size_t j=i+1; j<num_adj_vertices; j++) {
|
||||
Plane_3 separator(closest_point, adj_points[i], adj_points[j]);
|
||||
if (separator.is_degenerate()) {
|
||||
continue;
|
||||
}
|
||||
if (is_on_exterior(separator)) {
|
||||
if (!CGAL::collinear(
|
||||
query_point, adj_points[i], closest_point)) {
|
||||
d = vi;
|
||||
break;
|
||||
} else {
|
||||
d = adj_vertices[j];
|
||||
assert(!CGAL::collinear(
|
||||
query_point, adj_points[j], closest_point));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (d == std::numeric_limits<size_t>::max()) {
|
||||
Eigen::MatrixXd tmp_vertices(V.rows(), V.cols());
|
||||
for (size_t i=0; i<V.rows(); i++) {
|
||||
for (size_t j=0; j<V.cols(); j++) {
|
||||
tmp_vertices(i,j) = CGAL::to_double(V(i,j));
|
||||
}
|
||||
}
|
||||
Eigen::MatrixXi tmp_faces(adj_faces.size(), 3);
|
||||
for (size_t i=0; i<adj_faces.size(); i++) {
|
||||
tmp_faces.row(i) = F.row(adj_faces[i]);
|
||||
}
|
||||
//igl::writePLY("debug.ply", tmp_vertices, tmp_faces, false);
|
||||
throw std::runtime_error("Invalid vertex neighborhood");
|
||||
}
|
||||
const auto itr = v2f.equal_range(d);
|
||||
assert(itr.first != itr.second);
|
||||
|
||||
return process_edge_case(query_idx, s, d, itr.first->second, orientation);
|
||||
};
|
||||
|
||||
const size_t num_queries = P.rows();
|
||||
R.resize(num_queries, 1);
|
||||
S.resize(num_queries, 1);
|
||||
for (size_t i=0; i<num_queries; i++) {
|
||||
const Point_3 query(P(i,0), P(i,1), P(i,2));
|
||||
auto projection = tree.closest_point_and_primitive(query);
|
||||
const Point_3 closest_point = projection.first;
|
||||
size_t fid = projection.second - triangles.begin();
|
||||
bool fid_ori = false;
|
||||
|
||||
// Gether all facets sharing the closest point.
|
||||
typename std::vector<typename Tree::Primitive_id> intersected_faces;
|
||||
tree.all_intersected_primitives(Segment_3(closest_point, query),
|
||||
std::back_inserter(intersected_faces));
|
||||
const size_t num_intersected_faces = intersected_faces.size();
|
||||
std::vector<size_t> intersected_face_indices(num_intersected_faces);
|
||||
std::transform(intersected_faces.begin(),
|
||||
intersected_faces.end(),
|
||||
intersected_face_indices.begin(),
|
||||
[&](const typename Tree::Primitive_id& itr) -> size_t
|
||||
{ return I(itr-triangles.begin(), 0); });
|
||||
|
||||
size_t element_index;
|
||||
auto element_type = determine_element_type(closest_point, fid,
|
||||
element_index);
|
||||
switch(element_type) {
|
||||
case VERTEX:
|
||||
{
|
||||
const auto& f = F.row(I(fid, 0));
|
||||
const size_t s = f[element_index];
|
||||
fid = process_vertex_case(i, s, I(fid, 0), fid_ori);
|
||||
}
|
||||
break;
|
||||
case EDGE:
|
||||
{
|
||||
const auto& f = F.row(I(fid, 0));
|
||||
const size_t s = f[(element_index+1)%3];
|
||||
const size_t d = f[(element_index+2)%3];
|
||||
fid = process_edge_case(i, s, d, I(fid, 0), fid_ori);
|
||||
}
|
||||
break;
|
||||
case FACE:
|
||||
{
|
||||
fid = process_face_case(i, closest_point, fid, fid_ori);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unknown element type.");
|
||||
}
|
||||
|
||||
|
||||
R(i,0) = fid;
|
||||
S(i,0) = fid_ori;
|
||||
}
|
||||
}
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename uE2EType,
|
||||
typename DerivedEMAP,
|
||||
typename DerivedR,
|
||||
typename DerivedS >
|
||||
IGL_INLINE void igl::copyleft::cgal::closest_facet(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
Eigen::PlainObjectBase<DerivedR>& R,
|
||||
Eigen::PlainObjectBase<DerivedS>& S) {
|
||||
const size_t num_faces = F.rows();
|
||||
Eigen::VectorXi I = igl::LinSpaced<Eigen::VectorXi>(num_faces, 0, num_faces-1);
|
||||
igl::copyleft::cgal::closest_facet(V, F, I, P, uE2E, EMAP, R, S);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::closest_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, CGAL::Epeck, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, CGAL::AABB_tree<CGAL::AABB_traits<CGAL::Epeck, CGAL::AABB_triangle_primitive<CGAL::Epeck, std::vector<CGAL::Epeck::Triangle_3, std::allocator<CGAL::Epeck::Triangle_3> >::iterator, CGAL::Boolean_tag<false> > > > const&, std::vector<CGAL::Epeck::Triangle_3, std::allocator<CGAL::Epeck::Triangle_3> > const&, std::vector<bool, std::allocator<bool> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::closest_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, CGAL::Epeck, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, CGAL::AABB_tree<CGAL::AABB_traits<CGAL::Epeck, CGAL::AABB_triangle_primitive<CGAL::Epeck, std::vector<CGAL::Epeck::Triangle_3, std::allocator<CGAL::Epeck::Triangle_3> >::iterator, CGAL::Boolean_tag<false> > > > const&, std::vector<CGAL::Epeck::Triangle_3, std::allocator<CGAL::Epeck::Triangle_3> > const&, std::vector<bool, std::allocator<bool> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::closest_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#ifdef WIN32
|
||||
template void igl::copyleft::cgal::closest_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class CGAL::Epeck, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class CGAL::AABB_tree<class CGAL::AABB_traits<class CGAL::Epeck, class CGAL::AABB_triangle_primitive<class CGAL::Epeck, class std::_Vector_iterator<class std::_Vector_val<struct std::_Simple_types<class CGAL::Triangle_3<class CGAL::Epeck>>>>, struct CGAL::Boolean_tag<0>>>> const &, class std::vector<class CGAL::Triangle_3<class CGAL::Epeck>, class std::allocator<class CGAL::Triangle_3<class CGAL::Epeck>>> const &, class std::vector<bool, class std::allocator<bool>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::closest_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class CGAL::Epeck, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class CGAL::AABB_tree<class CGAL::AABB_traits<class CGAL::Epeck, class CGAL::AABB_triangle_primitive<class CGAL::Epeck, class std::_Vector_iterator<class std::_Vector_val<struct std::_Simple_types<class CGAL::Triangle_3<class CGAL::Epeck>>>>, struct CGAL::Boolean_tag<0>>>> const &, class std::vector<class CGAL::Triangle_3<class CGAL::Epeck>, class std::allocator<class CGAL::Triangle_3<class CGAL::Epeck>>> const &, class std::vector<bool, class std::allocator<bool>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::closest_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class CGAL::Epeck, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class CGAL::AABB_tree<class CGAL::AABB_traits<class CGAL::Epeck, class CGAL::AABB_triangle_primitive<class CGAL::Epeck, class std::_Vector_iterator<class std::_Vector_val<struct std::_Simple_types<class CGAL::Triangle_3<class CGAL::Epeck>>>>, struct CGAL::Boolean_tag<0>>>> const &, class std::vector<class CGAL::Triangle_3<class CGAL::Epeck>, class std::allocator<class CGAL::Triangle_3<class CGAL::Epeck>>> const &, class std::vector<bool, class std::allocator<bool>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
|
||||
#endif
|
||||
#endif
|
||||
110
src/libigl/igl/copyleft/cgal/closest_facet.h
Normal file
110
src/libigl/igl/copyleft/cgal/closest_facet.h
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
#ifndef IGL_COPYLET_CGAL_CLOSEST_FACET_H
|
||||
#define IGL_COPYLET_CGAL_CLOSEST_FACET_H
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
|
||||
#include <CGAL/AABB_tree.h>
|
||||
#include <CGAL/AABB_traits.h>
|
||||
#include <CGAL/AABB_triangle_primitive.h>
|
||||
#include <CGAL/intersections.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Determine the closest facet for each of the input points.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 array of vertices.
|
||||
// F #F by 3 array of faces.
|
||||
// I #I list of triangle indices to consider.
|
||||
// P #P by 3 array of query points.
|
||||
//
|
||||
// Outputs:
|
||||
// R #P list of closest facet indices.
|
||||
// S #P list of bools indicating on which side of the closest facet
|
||||
// each query point lies.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename DerivedP,
|
||||
typename uE2EType,
|
||||
typename DerivedEMAP,
|
||||
typename DerivedR,
|
||||
typename DerivedS >
|
||||
IGL_INLINE void closest_facet(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
Eigen::PlainObjectBase<DerivedR>& R,
|
||||
Eigen::PlainObjectBase<DerivedS>& S);
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename uE2EType,
|
||||
typename DerivedEMAP,
|
||||
typename DerivedR,
|
||||
typename DerivedS >
|
||||
IGL_INLINE void closest_facet(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
Eigen::PlainObjectBase<DerivedR>& R,
|
||||
Eigen::PlainObjectBase<DerivedS>& S);
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename DerivedP,
|
||||
typename uE2EType,
|
||||
typename DerivedEMAP,
|
||||
typename Kernel,
|
||||
typename DerivedR,
|
||||
typename DerivedS >
|
||||
IGL_INLINE void closest_facet(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
const std::vector<std::vector<size_t> > & VF,
|
||||
const std::vector<std::vector<size_t> > & VFi,
|
||||
const CGAL::AABB_tree<
|
||||
CGAL::AABB_traits<
|
||||
Kernel,
|
||||
CGAL::AABB_triangle_primitive<
|
||||
Kernel, typename std::vector<
|
||||
typename Kernel::Triangle_3 >::iterator > > > & tree,
|
||||
const std::vector<typename Kernel::Triangle_3 > & triangles,
|
||||
const std::vector<bool> & in_I,
|
||||
Eigen::PlainObjectBase<DerivedR>& R,
|
||||
Eigen::PlainObjectBase<DerivedS>& S);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
#include "closest_facet.cpp"
|
||||
#endif
|
||||
#endif
|
||||
152
src/libigl/igl/copyleft/cgal/complex_to_mesh.cpp
Normal file
152
src/libigl/igl/copyleft/cgal/complex_to_mesh.cpp
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "complex_to_mesh.h"
|
||||
|
||||
#include "../../centroid.h"
|
||||
#include "../../remove_unreferenced.h"
|
||||
|
||||
#include <CGAL/Surface_mesh_default_triangulation_3.h>
|
||||
#include <CGAL/Delaunay_triangulation_cell_base_with_circumcenter_3.h>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
|
||||
template <typename Tr, typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE bool igl::copyleft::cgal::complex_to_mesh(
|
||||
const CGAL::Complex_2_in_triangulation_3<Tr> & c2t3,
|
||||
Eigen::PlainObjectBase<DerivedV> & V,
|
||||
Eigen::PlainObjectBase<DerivedF> & F)
|
||||
{
|
||||
using namespace Eigen;
|
||||
// CGAL/IO/Complex_2_in_triangulation_3_file_writer.h
|
||||
using CGAL::Surface_mesher::number_of_facets_on_surface;
|
||||
|
||||
typedef typename CGAL::Complex_2_in_triangulation_3<Tr> C2t3;
|
||||
typedef typename Tr::Finite_facets_iterator Finite_facets_iterator;
|
||||
typedef typename Tr::Finite_vertices_iterator Finite_vertices_iterator;
|
||||
typedef typename Tr::Facet Facet;
|
||||
typedef typename Tr::Edge Edge;
|
||||
typedef typename Tr::Vertex_handle Vertex_handle;
|
||||
|
||||
// Header.
|
||||
const Tr& tr = c2t3.triangulation();
|
||||
|
||||
bool success = true;
|
||||
|
||||
const int n = tr.number_of_vertices();
|
||||
const int m = c2t3.number_of_facets();
|
||||
|
||||
assert(m == number_of_facets_on_surface(tr));
|
||||
|
||||
// Finite vertices coordinates.
|
||||
std::map<Vertex_handle, int> v2i;
|
||||
V.resize(n,3);
|
||||
{
|
||||
int v = 0;
|
||||
for(Finite_vertices_iterator vit = tr.finite_vertices_begin();
|
||||
vit != tr.finite_vertices_end();
|
||||
++vit)
|
||||
{
|
||||
V(v,0) = vit->point().x();
|
||||
V(v,1) = vit->point().y();
|
||||
V(v,2) = vit->point().z();
|
||||
v2i[vit] = v++;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Finite_facets_iterator fit = tr.finite_facets_begin();
|
||||
std::set<Facet> oriented_set;
|
||||
std::stack<Facet> stack;
|
||||
|
||||
while ((int)oriented_set.size() != m)
|
||||
{
|
||||
while ( fit->first->is_facet_on_surface(fit->second) == false ||
|
||||
oriented_set.find(*fit) != oriented_set.end() ||
|
||||
oriented_set.find(c2t3.opposite_facet(*fit)) !=
|
||||
oriented_set.end() )
|
||||
{
|
||||
++fit;
|
||||
}
|
||||
oriented_set.insert(*fit);
|
||||
stack.push(*fit);
|
||||
while(! stack.empty() )
|
||||
{
|
||||
Facet f = stack.top();
|
||||
stack.pop();
|
||||
for(int ih = 0 ; ih < 3 ; ++ih)
|
||||
{
|
||||
const int i1 = tr.vertex_triple_index(f.second, tr. cw(ih));
|
||||
const int i2 = tr.vertex_triple_index(f.second, tr.ccw(ih));
|
||||
|
||||
const typename C2t3::Face_status face_status
|
||||
= c2t3.face_status(Edge(f.first, i1, i2));
|
||||
if(face_status == C2t3::REGULAR)
|
||||
{
|
||||
Facet fn = c2t3.neighbor(f, ih);
|
||||
if (oriented_set.find(fn) == oriented_set.end())
|
||||
{
|
||||
if(oriented_set.find(c2t3.opposite_facet(fn)) == oriented_set.end())
|
||||
{
|
||||
oriented_set.insert(fn);
|
||||
stack.push(fn);
|
||||
}else {
|
||||
success = false; // non-orientable
|
||||
}
|
||||
}
|
||||
}else if(face_status != C2t3::BOUNDARY)
|
||||
{
|
||||
success = false; // non manifold, thus non-orientable
|
||||
}
|
||||
} // end "for each neighbor of f"
|
||||
} // end "stack non empty"
|
||||
} // end "oriented_set not full"
|
||||
|
||||
F.resize(m,3);
|
||||
int f = 0;
|
||||
for(typename std::set<Facet>::const_iterator fit =
|
||||
oriented_set.begin();
|
||||
fit != oriented_set.end();
|
||||
++fit)
|
||||
{
|
||||
const typename Tr::Cell_handle cell = fit->first;
|
||||
const int& index = fit->second;
|
||||
const int index1 = v2i[cell->vertex(tr.vertex_triple_index(index, 0))];
|
||||
const int index2 = v2i[cell->vertex(tr.vertex_triple_index(index, 1))];
|
||||
const int index3 = v2i[cell->vertex(tr.vertex_triple_index(index, 2))];
|
||||
// This order is flipped
|
||||
F(f,0) = index1;
|
||||
F(f,1) = index2;
|
||||
F(f,2) = index3;
|
||||
f++;
|
||||
}
|
||||
assert(f == m);
|
||||
} // end if(facets must be oriented)
|
||||
|
||||
// This CGAL code seems to randomly assign the global orientation
|
||||
// Flip based on the signed volume.
|
||||
Eigen::Vector3d cen;
|
||||
double vol;
|
||||
igl::centroid(V,F,cen,vol);
|
||||
if(vol < 0)
|
||||
{
|
||||
// Flip
|
||||
F = F.rowwise().reverse().eval();
|
||||
}
|
||||
|
||||
// CGAL code somehow can end up with unreferenced vertices
|
||||
{
|
||||
VectorXi _1;
|
||||
remove_unreferenced( MatrixXd(V), MatrixXi(F), V,F,_1);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
template bool igl::copyleft::cgal::complex_to_mesh<CGAL::Delaunay_triangulation_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_data_structure_3<CGAL::Surface_mesh_vertex_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_vertex_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_ds_vertex_base_3<void> > >, CGAL::Delaunay_triangulation_cell_base_with_circumcenter_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Surface_mesh_cell_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_cell_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_ds_cell_base_3<void> > > >, CGAL::Sequential_tag>, CGAL::Default, CGAL::Default>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(CGAL::Complex_2_in_triangulation_3<CGAL::Delaunay_triangulation_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_data_structure_3<CGAL::Surface_mesh_vertex_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_vertex_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_ds_vertex_base_3<void> > >, CGAL::Delaunay_triangulation_cell_base_with_circumcenter_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Surface_mesh_cell_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_cell_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_ds_cell_base_3<void> > > >, CGAL::Sequential_tag>, CGAL::Default, CGAL::Default>, void> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
47
src/libigl/igl/copyleft/cgal/complex_to_mesh.h
Normal file
47
src/libigl/igl/copyleft/cgal/complex_to_mesh.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_COMPLEX_TO_MESH_H
|
||||
#define IGL_COPYLEFT_CGAL_COMPLEX_TO_MESH_H
|
||||
#include "../../igl_inline.h"
|
||||
|
||||
#include <Eigen/Dense>
|
||||
#include <CGAL/Complex_2_in_triangulation_3.h>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Templates:
|
||||
// Tr CGAL triangulation type, e.g.
|
||||
// CGAL::Surface_mesh_default_triangulation_3
|
||||
// Inputs
|
||||
// c2t3 2-complex (surface) living in a 3d triangulation (e.g. result of
|
||||
// CGAL::make_surface_mesh)
|
||||
// Outputs:
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices
|
||||
// Returns true iff conversion was successful, failure can ok if CGAL code
|
||||
// can't figure out ordering.
|
||||
//
|
||||
template <typename Tr, typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE bool complex_to_mesh(
|
||||
const CGAL::Complex_2_in_triangulation_3<Tr> & c2t3,
|
||||
Eigen::PlainObjectBase<DerivedV> & V,
|
||||
Eigen::PlainObjectBase<DerivedF> & F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "complex_to_mesh.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
83
src/libigl/igl/copyleft/cgal/component_inside_component.cpp
Normal file
83
src/libigl/igl/copyleft/cgal/component_inside_component.cpp
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "component_inside_component.h"
|
||||
|
||||
#include "order_facets_around_edge.h"
|
||||
#include "../../LinSpaced.h"
|
||||
#include "points_inside_component.h"
|
||||
|
||||
#include <CGAL/AABB_tree.h>
|
||||
#include <CGAL/AABB_traits.h>
|
||||
#include <CGAL/AABB_triangle_primitive.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <list>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedI>
|
||||
IGL_INLINE bool igl::copyleft::cgal::component_inside_component(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V1,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F1,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I1,
|
||||
const Eigen::PlainObjectBase<DerivedV>& V2,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F2,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I2) {
|
||||
if (F1.rows() <= 0 || I1.rows() <= 0 || F2.rows() <= 0 || I2.rows() <= 0) {
|
||||
throw "Component inside test cannot be done on empty component!";
|
||||
}
|
||||
|
||||
const Eigen::Vector3i& f = F1.row(I1(0, 0));
|
||||
const Eigen::Matrix<typename DerivedV::Scalar, 1, 3> query(
|
||||
(V1(f[0],0) + V1(f[1],0) + V1(f[2],0))/3.0,
|
||||
(V1(f[0],1) + V1(f[1],1) + V1(f[2],1))/3.0,
|
||||
(V1(f[0],2) + V1(f[1],2) + V1(f[2],2))/3.0);
|
||||
Eigen::VectorXi inside;
|
||||
igl::copyleft::cgal::points_inside_component(V2, F2, I2, query, inside);
|
||||
assert(inside.size() == 1);
|
||||
return inside[0];
|
||||
}
|
||||
|
||||
template<typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE bool igl::copyleft::cgal::component_inside_component(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V1,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F1,
|
||||
const Eigen::PlainObjectBase<DerivedV>& V2,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F2) {
|
||||
if (F1.rows() <= 0 || F2.rows() <= 0) {
|
||||
throw "Component inside test cannot be done on empty component!";
|
||||
}
|
||||
Eigen::VectorXi I1(F1.rows()), I2(F2.rows());
|
||||
I1 = igl::LinSpaced<Eigen::VectorXi>(F1.rows(), 0, F1.rows()-1);
|
||||
I2 = igl::LinSpaced<Eigen::VectorXi>(F2.rows(), 0, F2.rows()-1);
|
||||
return igl::copyleft::cgal::component_inside_component(V1, F1, I1, V2, F2, I2);
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template bool igl::copyleft::cgal::component_inside_component<
|
||||
Eigen::Matrix<double, -1, -1, 0, -1, -1>,
|
||||
Eigen::Matrix< int, -1, -1, 0, -1, -1>,
|
||||
Eigen::Matrix< int, -1, -1, 0, -1, -1> > (
|
||||
Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&,
|
||||
Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&,
|
||||
Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&,
|
||||
Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&,
|
||||
Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&,
|
||||
Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&);
|
||||
|
||||
template bool igl::copyleft::cgal::component_inside_component<
|
||||
Eigen::Matrix<double, -1, -1, 0, -1, -1>,
|
||||
Eigen::Matrix< int, -1, -1, 0, -1, -1> > (
|
||||
Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&,
|
||||
Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&,
|
||||
Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&,
|
||||
Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&);
|
||||
#endif
|
||||
75
src/libigl/igl/copyleft/cgal/component_inside_component.h
Normal file
75
src/libigl/igl/copyleft/cgal/component_inside_component.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_COMONENT_INSIDE_COMPONENT
|
||||
#define IGL_COPYLEFT_CGAL_COMONENT_INSIDE_COMPONENT
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
|
||||
namespace igl {
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal {
|
||||
|
||||
// Determine if connected facet component (V1, F1, I1) is inside of
|
||||
// connected facet component (V2, F2, I2).
|
||||
//
|
||||
// Precondition:
|
||||
// Both components must represent closed, self-intersection free,
|
||||
// non-degenerated surfaces that are the boundary of 3D volumes. In
|
||||
// addition, (V1, F1, I1) must not intersect with (V2, F2, I2).
|
||||
//
|
||||
// Inputs:
|
||||
// V1 #V1 by 3 list of vertex position of mesh 1
|
||||
// F1 #F1 by 3 list of triangles indices into V1
|
||||
// I1 #I1 list of indices into F1, indicate the facets of component
|
||||
// V2 #V2 by 3 list of vertex position of mesh 2
|
||||
// F2 #F2 by 3 list of triangles indices into V2
|
||||
// I2 #I2 list of indices into F2, indicate the facets of component
|
||||
//
|
||||
// Outputs:
|
||||
// return true iff (V1, F1, I1) is entirely inside of (V2, F2, I2).
|
||||
template<typename DerivedV, typename DerivedF, typename DerivedI>
|
||||
IGL_INLINE bool component_inside_component(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V1,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F1,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I1,
|
||||
const Eigen::PlainObjectBase<DerivedV>& V2,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F2,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I2);
|
||||
|
||||
// Determine if mesh (V1, F1) is inside of mesh (V2, F2).
|
||||
//
|
||||
// Precondition:
|
||||
// Both meshes must be closed, self-intersection free, non-degenerated
|
||||
// surfaces that are the boundary of 3D volumes. They should not
|
||||
// intersect each other.
|
||||
//
|
||||
// Inputs:
|
||||
// V1 #V1 by 3 list of vertex position of mesh 1
|
||||
// F1 #F1 by 3 list of triangles indices into V1
|
||||
// V2 #V2 by 3 list of vertex position of mesh 2
|
||||
// F2 #F2 by 3 list of triangles indices into V2
|
||||
//
|
||||
// Outputs:
|
||||
// return true iff (V1, F1) is entirely inside of (V2, F2).
|
||||
template<typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE bool component_inside_component(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V1,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F1,
|
||||
const Eigen::PlainObjectBase<DerivedV>& V2,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
#include "component_inside_component.cpp"
|
||||
#endif
|
||||
#endif
|
||||
72
src/libigl/igl/copyleft/cgal/convex_hull.cpp
Normal file
72
src/libigl/igl/copyleft/cgal/convex_hull.cpp
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "convex_hull.h"
|
||||
#include "../../ismember.h"
|
||||
#include "polyhedron_to_mesh.h"
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include <CGAL/convex_hull_3.h>
|
||||
#include <vector>
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedW,
|
||||
typename DerivedG>
|
||||
IGL_INLINE void igl::copyleft::cgal::convex_hull(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::PlainObjectBase<DerivedW> & W,
|
||||
Eigen::PlainObjectBase<DerivedG> & G)
|
||||
{
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef K::Point_3 Point_3;
|
||||
//typedef CGAL::Delaunay_triangulation_3<K> Delaunay;
|
||||
//typedef Delaunay::Vertex_handle Vertex_handle;
|
||||
//typedef CGAL::Surface_mesh<Point_3> Surface_mesh;
|
||||
typedef CGAL::Polyhedron_3<K> Polyhedron_3;
|
||||
std::vector<Point_3> points(V.rows());
|
||||
for(int i = 0;i<V.rows();i++)
|
||||
{
|
||||
points[i] = Point_3(V(i,0),V(i,1),V(i,2));
|
||||
}
|
||||
Polyhedron_3 poly;
|
||||
CGAL::convex_hull_3(points.begin(),points.end(),poly);
|
||||
assert(poly.is_pure_triangle() && "Assuming CGAL outputs a triangle mesh");
|
||||
polyhedron_to_mesh(poly,W,G);
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF>
|
||||
IGL_INLINE void igl::copyleft::cgal::convex_hull(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::PlainObjectBase<DerivedF> & F)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic> W;
|
||||
Eigen::Matrix<typename DerivedF::Scalar, Eigen::Dynamic, Eigen::Dynamic> G;
|
||||
convex_hull(V,W,G);
|
||||
// This is a lazy way to reindex into the original mesh
|
||||
Eigen::Matrix<bool,Eigen::Dynamic,1> I;
|
||||
Eigen::VectorXi J;
|
||||
igl::ismember_rows(W,V,I,J);
|
||||
assert(I.all() && "Should find all W in V");
|
||||
F.resizeLike(G);
|
||||
for(int f = 0;f<G.rows();f++)
|
||||
{
|
||||
for(int c = 0;c<3;c++)
|
||||
{
|
||||
F(f,c) = J(G(f,c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::convex_hull<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
56
src/libigl/igl/copyleft/cgal/convex_hull.h
Normal file
56
src/libigl/igl/copyleft/cgal/convex_hull.h
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_CONVEX_HULL_H
|
||||
#define IGL_COPYLEFT_CGAL_CONVEX_HULL_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Given a set of points (V), compute the convex hull as a triangle mesh (W,G)
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of input points
|
||||
// Outputs:
|
||||
// W #W by 3 list of convex hull points
|
||||
// G #G by 3 list of triangle indices into W
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedW,
|
||||
typename DerivedG>
|
||||
IGL_INLINE void convex_hull(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::PlainObjectBase<DerivedW> & W,
|
||||
Eigen::PlainObjectBase<DerivedG> & G);
|
||||
// Given a set of points (V), compute the convex hull as a triangle mesh (F)
|
||||
// over input vertex set (V)
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of input points
|
||||
// Outputs:
|
||||
// F #F by 3 list of triangle indices into V
|
||||
//
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF>
|
||||
IGL_INLINE void convex_hull(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::PlainObjectBase<DerivedF> & F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "convex_hull.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
62
src/libigl/igl/copyleft/cgal/delaunay_triangulation.cpp
Normal file
62
src/libigl/igl/copyleft/cgal/delaunay_triangulation.cpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2018 Alec Jacobson
|
||||
// Copyright (C) 2016 Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "delaunay_triangulation.h"
|
||||
#include "../../delaunay_triangulation.h"
|
||||
#include "orient2D.h"
|
||||
#include "incircle.h"
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF>
|
||||
IGL_INLINE void igl::copyleft::cgal::delaunay_triangulation(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
Eigen::PlainObjectBase<DerivedF>& F)
|
||||
{
|
||||
typedef typename DerivedV::Scalar Scalar;
|
||||
igl::delaunay_triangulation(V, orient2D<Scalar>, incircle<Scalar>, F);
|
||||
// This function really exists to test our igl::delaunay_triangulation
|
||||
//
|
||||
// It's currently much faster to call cgal's native Delaunay routine
|
||||
//
|
||||
//#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
//#include <CGAL/Delaunay_triangulation_2.h>
|
||||
//#include <CGAL/Triangulation_vertex_base_with_info_2.h>
|
||||
//#include <vector>
|
||||
// const auto delaunay =
|
||||
// [&](const Eigen::MatrixXd & V,Eigen::MatrixXi & F)
|
||||
// {
|
||||
// typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||
// typedef CGAL::Triangulation_vertex_base_with_info_2<unsigned int, Kernel> Vb;
|
||||
// typedef CGAL::Triangulation_data_structure_2<Vb> Tds;
|
||||
// typedef CGAL::Delaunay_triangulation_2<Kernel, Tds> Delaunay;
|
||||
// typedef Kernel::Point_2 Point;
|
||||
// std::vector< std::pair<Point,unsigned> > points(V.rows());
|
||||
// for(int i = 0;i<V.rows();i++)
|
||||
// {
|
||||
// points[i] = std::make_pair(Point(V(i,0),V(i,1)),i);
|
||||
// }
|
||||
// Delaunay triangulation;
|
||||
// triangulation.insert(points.begin(),points.end());
|
||||
// F.resize(triangulation.number_of_faces(),3);
|
||||
// {
|
||||
// int j = 0;
|
||||
// for(Delaunay::Finite_faces_iterator fit = triangulation.finite_faces_begin();
|
||||
// fit != triangulation.finite_faces_end(); ++fit)
|
||||
// {
|
||||
// Delaunay::Face_handle face = fit;
|
||||
// F(j,0) = face->vertex(0)->info();
|
||||
// F(j,1) = face->vertex(1)->info();
|
||||
// F(j,2) = face->vertex(2)->info();
|
||||
// j++;
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
}
|
||||
|
||||
47
src/libigl/igl/copyleft/cgal/delaunay_triangulation.h
Normal file
47
src/libigl/igl/copyleft/cgal/delaunay_triangulation.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef IGL_COPYLEFT_CGAL_DELAUNAY_TRIANGULATION_H
|
||||
#define IGL_COPYLEFT_CGAL_DELAUNAY_TRIANGULATION_H
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
|
||||
// Given a set of points in 2D, return a Delaunay triangulation of these
|
||||
// points.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 2 list of vertex positions
|
||||
//
|
||||
// Outputs:
|
||||
// F #F by 3 of faces in Delaunay triangulation.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF
|
||||
>
|
||||
IGL_INLINE void delaunay_triangulation(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
Eigen::PlainObjectBase<DerivedF>& F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "delaunay_triangulation.cpp"
|
||||
#endif
|
||||
#endif
|
||||
547
src/libigl/igl/copyleft/cgal/extract_cells.cpp
Normal file
547
src/libigl/igl/copyleft/cgal/extract_cells.cpp
Normal file
|
|
@ -0,0 +1,547 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
#include "extract_cells.h"
|
||||
#include "closest_facet.h"
|
||||
#include "order_facets_around_edge.h"
|
||||
#include "outer_facet.h"
|
||||
#include "submesh_aabb_tree.h"
|
||||
#include "../../extract_manifold_patches.h"
|
||||
#include "../../facet_components.h"
|
||||
#include "../../get_seconds.h"
|
||||
#include "../../triangle_triangle_adjacency.h"
|
||||
#include "../../unique_edge_map.h"
|
||||
#include "../../vertex_triangle_adjacency.h"
|
||||
|
||||
#include <CGAL/AABB_tree.h>
|
||||
#include <CGAL/AABB_traits.h>
|
||||
#include <CGAL/AABB_triangle_primitive.h>
|
||||
#include <CGAL/intersections.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
//#define EXTRACT_CELLS_DEBUG
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedC >
|
||||
IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedC>& cells)
|
||||
{
|
||||
const size_t num_faces = F.rows();
|
||||
// Construct edge adjacency
|
||||
Eigen::MatrixXi E, uE;
|
||||
Eigen::VectorXi EMAP;
|
||||
std::vector<std::vector<size_t> > uE2E;
|
||||
igl::unique_edge_map(F, E, uE, EMAP, uE2E);
|
||||
// Cluster into manifold patches
|
||||
Eigen::VectorXi P;
|
||||
igl::extract_manifold_patches(F, EMAP, uE2E, P);
|
||||
// Extract cells
|
||||
DerivedC per_patch_cells;
|
||||
const size_t num_cells =
|
||||
igl::copyleft::cgal::extract_cells(V,F,P,E,uE,uE2E,EMAP,per_patch_cells);
|
||||
// Distribute per-patch cell information to each face
|
||||
cells.resize(num_faces, 2);
|
||||
for (size_t i=0; i<num_faces; i++)
|
||||
{
|
||||
cells.row(i) = per_patch_cells.row(P[i]);
|
||||
}
|
||||
return num_cells;
|
||||
}
|
||||
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename DerivedE,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename DerivedEMAP,
|
||||
typename DerivedC >
|
||||
IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const Eigen::PlainObjectBase<DerivedE>& E,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
Eigen::PlainObjectBase<DerivedC>& cells)
|
||||
{
|
||||
// Trivial base case
|
||||
if(P.size() == 0)
|
||||
{
|
||||
assert(F.size() == 0);
|
||||
cells.resize(0,2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
|
||||
typedef Kernel::Point_3 Point_3;
|
||||
typedef Kernel::Plane_3 Plane_3;
|
||||
typedef Kernel::Segment_3 Segment_3;
|
||||
typedef Kernel::Triangle_3 Triangle;
|
||||
typedef std::vector<Triangle>::iterator Iterator;
|
||||
typedef CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
|
||||
typedef CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
|
||||
typedef CGAL::AABB_tree<AABB_triangle_traits> Tree;
|
||||
|
||||
#ifdef EXTRACT_CELLS_DEBUG
|
||||
const auto & tictoc = []() -> double
|
||||
{
|
||||
static double t_start = igl::get_seconds();
|
||||
double diff = igl::get_seconds()-t_start;
|
||||
t_start += diff;
|
||||
return diff;
|
||||
};
|
||||
const auto log_time = [&](const std::string& label) -> void {
|
||||
std::cout << "extract_cells." << label << ": "
|
||||
<< tictoc() << std::endl;
|
||||
};
|
||||
tictoc();
|
||||
#else
|
||||
// no-op
|
||||
const auto log_time = [](const std::string){};
|
||||
#endif
|
||||
const size_t num_faces = F.rows();
|
||||
typedef typename DerivedF::Scalar Index;
|
||||
assert(P.size() > 0);
|
||||
const size_t num_patches = P.maxCoeff()+1;
|
||||
|
||||
// Extract all cells...
|
||||
DerivedC raw_cells;
|
||||
const size_t num_raw_cells =
|
||||
extract_cells_single_component(V,F,P,uE,uE2E,EMAP,raw_cells);
|
||||
log_time("extract_single_component_cells");
|
||||
|
||||
// Compute triangle-triangle adjacency data-structure
|
||||
std::vector<std::vector<std::vector<Index > > > TT,_1;
|
||||
igl::triangle_triangle_adjacency(E, EMAP, uE2E, false, TT, _1);
|
||||
log_time("compute_face_adjacency");
|
||||
|
||||
// Compute connected components of the mesh
|
||||
Eigen::VectorXi C, counts;
|
||||
igl::facet_components(TT, C, counts);
|
||||
log_time("form_components");
|
||||
|
||||
const size_t num_components = counts.size();
|
||||
// components[c] --> list of face indices into F of faces in component c
|
||||
std::vector<std::vector<size_t> > components(num_components);
|
||||
// Loop over all faces
|
||||
for (size_t i=0; i<num_faces; i++)
|
||||
{
|
||||
components[C[i]].push_back(i);
|
||||
}
|
||||
// Convert vector lists to Eigen lists...
|
||||
// and precompute data-structures for each component
|
||||
std::vector<std::vector<size_t> > VF,VFi;
|
||||
igl::vertex_triangle_adjacency(V.rows(), F, VF, VFi);
|
||||
std::vector<Eigen::VectorXi> Is(num_components);
|
||||
std::vector<
|
||||
CGAL::AABB_tree<
|
||||
CGAL::AABB_traits<
|
||||
Kernel,
|
||||
CGAL::AABB_triangle_primitive<
|
||||
Kernel, std::vector<
|
||||
Kernel::Triangle_3 >::iterator > > > > trees(num_components);
|
||||
std::vector< std::vector<Kernel::Triangle_3 > >
|
||||
triangle_lists(num_components);
|
||||
std::vector<std::vector<bool> > in_Is(num_components);
|
||||
|
||||
// Find outer facets, their orientations and cells for each component
|
||||
Eigen::VectorXi outer_facets(num_components);
|
||||
Eigen::VectorXi outer_facet_orientation(num_components);
|
||||
Eigen::VectorXi outer_cells(num_components);
|
||||
for (size_t i=0; i<num_components; i++)
|
||||
{
|
||||
Is[i].resize(components[i].size());
|
||||
std::copy(components[i].begin(), components[i].end(),Is[i].data());
|
||||
bool flipped;
|
||||
igl::copyleft::cgal::outer_facet(V, F, Is[i], outer_facets[i], flipped);
|
||||
outer_facet_orientation[i] = flipped?1:0;
|
||||
outer_cells[i] = raw_cells(P[outer_facets[i]], outer_facet_orientation[i]);
|
||||
}
|
||||
#ifdef EXTRACT_CELLS_DEBUG
|
||||
log_time("outer_facet_per_component");
|
||||
#endif
|
||||
|
||||
// Compute barycenter of a triangle in mesh (V,F)
|
||||
//
|
||||
// Inputs:
|
||||
// fid index into F
|
||||
// Returns row-vector of barycenter coordinates
|
||||
const auto get_triangle_center = [&V,&F](const size_t fid)
|
||||
{
|
||||
return ((V.row(F(fid,0))+V.row(F(fid,1))+V.row(F(fid,2)))/3.0).eval();
|
||||
};
|
||||
std::vector<std::vector<size_t> > nested_cells(num_raw_cells);
|
||||
std::vector<std::vector<size_t> > ambient_cells(num_raw_cells);
|
||||
std::vector<std::vector<size_t> > ambient_comps(num_components);
|
||||
// Only bother if there's more than one component
|
||||
if(num_components > 1)
|
||||
{
|
||||
// construct bounding boxes for each component
|
||||
DerivedV bbox_min(num_components, 3);
|
||||
DerivedV bbox_max(num_components, 3);
|
||||
// Assuming our mesh (in exact numbers) fits in the range of double.
|
||||
bbox_min.setConstant(std::numeric_limits<double>::max());
|
||||
bbox_max.setConstant(std::numeric_limits<double>::min());
|
||||
// Loop over faces
|
||||
for (size_t i=0; i<num_faces; i++)
|
||||
{
|
||||
// component of this face
|
||||
const auto comp_id = C[i];
|
||||
const auto& f = F.row(i);
|
||||
for (size_t j=0; j<3; j++)
|
||||
{
|
||||
for(size_t d=0;d<3;d++)
|
||||
{
|
||||
bbox_min(comp_id,d) = std::min(bbox_min(comp_id,d), V(f[j],d));
|
||||
bbox_max(comp_id,d) = std::max(bbox_max(comp_id,d), V(f[j],d));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return true if box of component ci intersects that of cj
|
||||
const auto bbox_intersects = [&bbox_max,&bbox_min](size_t ci, size_t cj)
|
||||
{
|
||||
return !(
|
||||
bbox_max(ci,0) < bbox_min(cj,0) ||
|
||||
bbox_max(ci,1) < bbox_min(cj,1) ||
|
||||
bbox_max(ci,2) < bbox_min(cj,2) ||
|
||||
bbox_max(cj,0) < bbox_min(ci,0) ||
|
||||
bbox_max(cj,1) < bbox_min(ci,1) ||
|
||||
bbox_max(cj,2) < bbox_min(ci,2));
|
||||
};
|
||||
|
||||
// Loop over components. This section is O(m²)
|
||||
for (size_t i=0; i<num_components; i++)
|
||||
{
|
||||
// List of components that could overlap with component i
|
||||
std::vector<size_t> candidate_comps;
|
||||
candidate_comps.reserve(num_components);
|
||||
// Loop over components
|
||||
for (size_t j=0; j<num_components; j++)
|
||||
{
|
||||
if (i == j) continue;
|
||||
if (bbox_intersects(i,j)) candidate_comps.push_back(j);
|
||||
}
|
||||
|
||||
const size_t num_candidate_comps = candidate_comps.size();
|
||||
if (num_candidate_comps == 0) continue;
|
||||
|
||||
// Build aabb tree for this component.
|
||||
submesh_aabb_tree(V,F,Is[i],trees[i],triangle_lists[i],in_Is[i]);
|
||||
|
||||
// Get query points on each candidate component: barycenter of
|
||||
// outer-facet
|
||||
DerivedV queries(num_candidate_comps, 3);
|
||||
for (size_t j=0; j<num_candidate_comps; j++)
|
||||
{
|
||||
const size_t index = candidate_comps[j];
|
||||
queries.row(j) = get_triangle_center(outer_facets[index]);
|
||||
}
|
||||
|
||||
// Gather closest facets in ith component to each query point and their
|
||||
// orientations
|
||||
const auto& I = Is[i];
|
||||
const auto& tree = trees[i];
|
||||
const auto& in_I = in_Is[i];
|
||||
const auto& triangles = triangle_lists[i];
|
||||
|
||||
Eigen::VectorXi closest_facets, closest_facet_orientations;
|
||||
closest_facet(
|
||||
V,
|
||||
F,
|
||||
I,
|
||||
queries,
|
||||
uE2E,
|
||||
EMAP,
|
||||
VF,
|
||||
VFi,
|
||||
tree,
|
||||
triangles,
|
||||
in_I,
|
||||
closest_facets,
|
||||
closest_facet_orientations);
|
||||
// Loop over all candidates
|
||||
for (size_t j=0; j<num_candidate_comps; j++)
|
||||
{
|
||||
const size_t index = candidate_comps[j];
|
||||
const size_t closest_patch = P[closest_facets[j]];
|
||||
const size_t closest_patch_side = closest_facet_orientations[j] ? 0:1;
|
||||
// The cell id of the closest patch
|
||||
const size_t ambient_cell =
|
||||
raw_cells(closest_patch,closest_patch_side);
|
||||
if (ambient_cell != (size_t)outer_cells[i])
|
||||
{
|
||||
// ---> component index inside component i, because the cell of the
|
||||
// closest facet on i to component index is **not** the same as the
|
||||
// "outer cell" of component i: component index is **not** outside of
|
||||
// component i (therefore it's inside).
|
||||
nested_cells[ambient_cell].push_back(outer_cells[index]);
|
||||
ambient_cells[outer_cells[index]].push_back(ambient_cell);
|
||||
ambient_comps[index].push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef EXTRACT_CELLS_DEBUG
|
||||
log_time("nested_relationship");
|
||||
#endif
|
||||
|
||||
const size_t INVALID = std::numeric_limits<size_t>::max();
|
||||
const size_t INFINITE_CELL = num_raw_cells;
|
||||
std::vector<size_t> embedded_cells(num_raw_cells, INVALID);
|
||||
for (size_t i=0; i<num_components; i++) {
|
||||
const size_t outer_cell = outer_cells[i];
|
||||
const auto& ambient_comps_i = ambient_comps[i];
|
||||
const auto& ambient_cells_i = ambient_cells[outer_cell];
|
||||
const size_t num_ambient_comps = ambient_comps_i.size();
|
||||
assert(num_ambient_comps == ambient_cells_i.size());
|
||||
if (num_ambient_comps > 0) {
|
||||
size_t embedded_comp = INVALID;
|
||||
size_t embedded_cell = INVALID;
|
||||
for (size_t j=0; j<num_ambient_comps; j++) {
|
||||
if (ambient_comps[ambient_comps_i[j]].size() ==
|
||||
num_ambient_comps-1) {
|
||||
embedded_comp = ambient_comps_i[j];
|
||||
embedded_cell = ambient_cells_i[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(embedded_comp != INVALID);
|
||||
assert(embedded_cell != INVALID);
|
||||
embedded_cells[outer_cell] = embedded_cell;
|
||||
} else {
|
||||
embedded_cells[outer_cell] = INFINITE_CELL;
|
||||
}
|
||||
}
|
||||
for (size_t i=0; i<num_patches; i++) {
|
||||
if (embedded_cells[raw_cells(i,0)] != INVALID) {
|
||||
raw_cells(i,0) = embedded_cells[raw_cells(i, 0)];
|
||||
}
|
||||
if (embedded_cells[raw_cells(i,1)] != INVALID) {
|
||||
raw_cells(i,1) = embedded_cells[raw_cells(i, 1)];
|
||||
}
|
||||
}
|
||||
|
||||
size_t count = 0;
|
||||
std::vector<size_t> mapped_indices(num_raw_cells+1, INVALID);
|
||||
// Always map infinite cell to index 0.
|
||||
mapped_indices[INFINITE_CELL] = count;
|
||||
count++;
|
||||
|
||||
for (size_t i=0; i<num_patches; i++) {
|
||||
const size_t old_positive_cell_id = raw_cells(i, 0);
|
||||
const size_t old_negative_cell_id = raw_cells(i, 1);
|
||||
size_t positive_cell_id, negative_cell_id;
|
||||
if (mapped_indices[old_positive_cell_id] == INVALID) {
|
||||
mapped_indices[old_positive_cell_id] = count;
|
||||
positive_cell_id = count;
|
||||
count++;
|
||||
} else {
|
||||
positive_cell_id = mapped_indices[old_positive_cell_id];
|
||||
}
|
||||
if (mapped_indices[old_negative_cell_id] == INVALID) {
|
||||
mapped_indices[old_negative_cell_id] = count;
|
||||
negative_cell_id = count;
|
||||
count++;
|
||||
} else {
|
||||
negative_cell_id = mapped_indices[old_negative_cell_id];
|
||||
}
|
||||
raw_cells(i, 0) = positive_cell_id;
|
||||
raw_cells(i, 1) = negative_cell_id;
|
||||
}
|
||||
cells = raw_cells;
|
||||
#ifdef EXTRACT_CELLS_DEBUG
|
||||
log_time("finalize");
|
||||
#endif
|
||||
return count;
|
||||
}
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename DerivedEMAP,
|
||||
typename DerivedC>
|
||||
IGL_INLINE size_t igl::copyleft::cgal::extract_cells_single_component(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
Eigen::PlainObjectBase<DerivedC>& cells)
|
||||
{
|
||||
const size_t num_faces = F.rows();
|
||||
// Input:
|
||||
// index index into #F*3 list of undirect edges
|
||||
// Returns index into face
|
||||
const auto edge_index_to_face_index = [&num_faces](size_t index)
|
||||
{
|
||||
return index % num_faces;
|
||||
};
|
||||
// Determine if a face (containing undirected edge {s,d} is consistently
|
||||
// oriented with directed edge {s,d} (or otherwise it is with {d,s})
|
||||
//
|
||||
// Inputs:
|
||||
// fid face index into F
|
||||
// s source index of edge
|
||||
// d destination index of edge
|
||||
// Returns true if face F(fid,:) is consistent with {s,d}
|
||||
const auto is_consistent =
|
||||
[&F](const size_t fid, const size_t s, const size_t d) -> bool
|
||||
{
|
||||
if ((size_t)F(fid, 0) == s && (size_t)F(fid, 1) == d) return false;
|
||||
if ((size_t)F(fid, 1) == s && (size_t)F(fid, 2) == d) return false;
|
||||
if ((size_t)F(fid, 2) == s && (size_t)F(fid, 0) == d) return false;
|
||||
|
||||
if ((size_t)F(fid, 0) == d && (size_t)F(fid, 1) == s) return true;
|
||||
if ((size_t)F(fid, 1) == d && (size_t)F(fid, 2) == s) return true;
|
||||
if ((size_t)F(fid, 2) == d && (size_t)F(fid, 0) == s) return true;
|
||||
throw "Invalid face!";
|
||||
return false;
|
||||
};
|
||||
|
||||
const size_t num_unique_edges = uE.rows();
|
||||
const size_t num_patches = P.maxCoeff() + 1;
|
||||
|
||||
// Build patch-patch adjacency list.
|
||||
std::vector<std::map<size_t, size_t> > patch_adj(num_patches);
|
||||
for (size_t i=0; i<num_unique_edges; i++) {
|
||||
const size_t s = uE(i,0);
|
||||
const size_t d = uE(i,1);
|
||||
const auto adj_faces = uE2E[i];
|
||||
const size_t num_adj_faces = adj_faces.size();
|
||||
if (num_adj_faces > 2) {
|
||||
for (size_t j=0; j<num_adj_faces; j++) {
|
||||
const size_t patch_j = P[edge_index_to_face_index(adj_faces[j])];
|
||||
for (size_t k=j+1; k<num_adj_faces; k++) {
|
||||
const size_t patch_k = P[edge_index_to_face_index(adj_faces[k])];
|
||||
if (patch_adj[patch_j].find(patch_k) == patch_adj[patch_j].end()) {
|
||||
patch_adj[patch_j].insert({patch_k, i});
|
||||
}
|
||||
if (patch_adj[patch_k].find(patch_j) == patch_adj[patch_k].end()) {
|
||||
patch_adj[patch_k].insert({patch_j, i});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const int INVALID = std::numeric_limits<int>::max();
|
||||
std::vector<size_t> cell_labels(num_patches * 2);
|
||||
for (size_t i=0; i<num_patches; i++) cell_labels[i] = i;
|
||||
std::vector<std::set<size_t> > equivalent_cells(num_patches*2);
|
||||
std::vector<bool> processed(num_unique_edges, false);
|
||||
|
||||
size_t label_count=0;
|
||||
for (size_t i=0; i<num_patches; i++) {
|
||||
for (const auto& entry : patch_adj[i]) {
|
||||
const size_t neighbor_patch = entry.first;
|
||||
const size_t uei = entry.second;
|
||||
if (processed[uei]) continue;
|
||||
processed[uei] = true;
|
||||
|
||||
const auto& adj_faces = uE2E[uei];
|
||||
const size_t num_adj_faces = adj_faces.size();
|
||||
assert(num_adj_faces > 2);
|
||||
|
||||
const size_t s = uE(uei,0);
|
||||
const size_t d = uE(uei,1);
|
||||
|
||||
std::vector<int> signed_adj_faces;
|
||||
for (auto ej : adj_faces)
|
||||
{
|
||||
const size_t fid = edge_index_to_face_index(ej);
|
||||
bool cons = is_consistent(fid, s, d);
|
||||
signed_adj_faces.push_back((fid+1)*(cons ? 1:-1));
|
||||
}
|
||||
{
|
||||
// Sort adjacent faces cyclically around {s,d}
|
||||
Eigen::VectorXi order;
|
||||
// order[f] will reveal the order of face f in signed_adj_faces
|
||||
order_facets_around_edge(V, F, s, d, signed_adj_faces, order);
|
||||
for (size_t j=0; j<num_adj_faces; j++) {
|
||||
const size_t curr_idx = j;
|
||||
const size_t next_idx = (j+1)%num_adj_faces;
|
||||
const size_t curr_patch_idx =
|
||||
P[edge_index_to_face_index(adj_faces[order[curr_idx]])];
|
||||
const size_t next_patch_idx =
|
||||
P[edge_index_to_face_index(adj_faces[order[next_idx]])];
|
||||
const bool curr_cons = signed_adj_faces[order[curr_idx]] > 0;
|
||||
const bool next_cons = signed_adj_faces[order[next_idx]] > 0;
|
||||
const size_t curr_cell_idx = curr_patch_idx*2 + (curr_cons?0:1);
|
||||
const size_t next_cell_idx = next_patch_idx*2 + (next_cons?1:0);
|
||||
equivalent_cells[curr_cell_idx].insert(next_cell_idx);
|
||||
equivalent_cells[next_cell_idx].insert(curr_cell_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t count=0;
|
||||
cells.resize(num_patches, 2);
|
||||
cells.setConstant(INVALID);
|
||||
const auto extract_equivalent_cells = [&](size_t i) {
|
||||
if (cells(i/2, i%2) != INVALID) return;
|
||||
std::queue<size_t> Q;
|
||||
Q.push(i);
|
||||
cells(i/2, i%2) = count;
|
||||
while (!Q.empty()) {
|
||||
const size_t index = Q.front();
|
||||
Q.pop();
|
||||
for (const auto j : equivalent_cells[index]) {
|
||||
if (cells(j/2, j%2) == INVALID) {
|
||||
cells(j/2, j%2) = count;
|
||||
Q.push(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
count++;
|
||||
};
|
||||
for (size_t i=0; i<num_patches; i++) {
|
||||
extract_equivalent_cells(i*2);
|
||||
extract_equivalent_cells(i*2+1);
|
||||
}
|
||||
|
||||
assert((cells.array() != INVALID).all());
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template unsigned long igl::copyleft::cgal::extract_cells<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template unsigned long igl::copyleft::cgal::extract_cells<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
template unsigned long igl::copyleft::cgal::extract_cells<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template unsigned long igl::copyleft::cgal::extract_cells<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
#ifdef WIN32
|
||||
template unsigned __int64 igl::copyleft::cgal::extract_cells<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &);
|
||||
template unsigned __int64 igl::copyleft::cgal::extract_cells<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &);
|
||||
template unsigned __int64 igl::copyleft::cgal::extract_cells<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &);
|
||||
#endif
|
||||
#endif
|
||||
116
src/libigl/igl/copyleft/cgal/extract_cells.h
Normal file
116
src/libigl/igl/copyleft/cgal/extract_cells.h
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
#ifndef IGL_COPYLEFT_CGAL_EXTRACT_CELLS
|
||||
#define IGL_COPYLEFT_CGAL_EXTRACT_CELLS
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
|
||||
namespace igl {
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Extract connected 3D space partitioned by mesh (V, F).
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 array of vertices.
|
||||
// F #F by 3 array of faces.
|
||||
//
|
||||
// Output:
|
||||
// cells #F by 2 array of cell indices. cells(i,0) represents the
|
||||
// cell index on the positive side of face i, and cells(i,1)
|
||||
// represents cell index of the negqtive side.
|
||||
// By convension cell with index 0 is the infinite cell.
|
||||
// Returns the number of cells
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedC >
|
||||
IGL_INLINE size_t extract_cells(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedC>& cells);
|
||||
|
||||
// Extract connected 3D space partitioned by mesh (V, F).
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 array of vertices.
|
||||
// F #F by 3 array of faces.
|
||||
// P #F list of patch indices.
|
||||
// E #E by 2 array of vertex indices, one edge per row.
|
||||
// uE #uE by 2 list of vertex_indices, represents undirected edges.
|
||||
// uE2E #uE list of lists that maps uE to E. (a one-to-many map)
|
||||
// EMAP #F*3 list of indices into uE.
|
||||
//
|
||||
// Output:
|
||||
// cells #P by 2 array of cell indices. cells(i,0) represents the
|
||||
// cell index on the positive side of patch i, and cells(i,1)
|
||||
// represents cell index of the negqtive side.
|
||||
// By convension cell with index 0 is the infinite cell.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename DerivedE,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename DerivedEMAP,
|
||||
typename DerivedC >
|
||||
IGL_INLINE size_t extract_cells(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const Eigen::PlainObjectBase<DerivedE>& E,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
Eigen::PlainObjectBase<DerivedC>& cells);
|
||||
|
||||
// Extract connected 3D space partitioned by mesh (V,F) composed of
|
||||
// **possibly multiple components** (the name of this function is
|
||||
// dubious).
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 array of vertices.
|
||||
// F #F by 3 array of faces.
|
||||
// P #F list of patch indices.
|
||||
// E #E by 2 array of vertex indices, one edge per row.
|
||||
// uE #uE by 2 list of vertex_indices, represents undirected edges.
|
||||
// uE2E #uE list of lists that maps uE to E. (a one-to-many map)
|
||||
// EMAP #F*3 list of indices into uE.
|
||||
// Output:
|
||||
// cells #P by 2 array of cell indices. cells(i,0) represents the
|
||||
// cell index on the positive side of patch i, and cells(i,1)
|
||||
// represents cell index of the negative side.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename DerivedEMAP,
|
||||
typename DerivedC >
|
||||
IGL_INLINE size_t extract_cells_single_component(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
||||
Eigen::PlainObjectBase<DerivedC>& cells);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "extract_cells.cpp"
|
||||
#endif
|
||||
#endif
|
||||
123
src/libigl/igl/copyleft/cgal/extract_feature.cpp
Normal file
123
src/libigl/igl/copyleft/cgal/extract_feature.cpp
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "extract_feature.h"
|
||||
#include <igl/unique_edge_map.h>
|
||||
#include <CGAL/Kernel/global_functions.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedE >
|
||||
IGL_INLINE void igl::copyleft::cgal::extract_feature(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const double tol,
|
||||
Eigen::PlainObjectBase<DerivedE>& feature_edges) {
|
||||
|
||||
using IndexType = typename DerivedE::Scalar;
|
||||
DerivedE E, uE;
|
||||
Eigen::VectorXi EMAP;
|
||||
std::vector<std::vector<IndexType> > uE2E;
|
||||
igl::unique_edge_map(F, E, uE, EMAP, uE2E);
|
||||
|
||||
igl::copyleft::cgal::extract_feature(V, F, tol, E, uE, uE2E, feature_edges);
|
||||
}
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedE >
|
||||
IGL_INLINE void igl::copyleft::cgal::extract_feature(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const double tol,
|
||||
const Eigen::PlainObjectBase<DerivedE>& E,
|
||||
const Eigen::PlainObjectBase<DerivedE>& uE,
|
||||
const std::vector<std::vector<typename DerivedE::Scalar> >& uE2E,
|
||||
Eigen::PlainObjectBase<DerivedE>& feature_edges) {
|
||||
|
||||
assert(V.cols() == 3);
|
||||
assert(F.cols() == 3);
|
||||
using Scalar = typename DerivedV::Scalar;
|
||||
using IndexType = typename DerivedE::Scalar;
|
||||
using Vertex = Eigen::Matrix<Scalar, 3, 1>;
|
||||
using Kernel = typename CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
using Point = typename Kernel::Point_3;
|
||||
|
||||
const size_t num_unique_edges = uE.rows();
|
||||
const size_t num_faces = F.rows();
|
||||
// NOTE: CGAL's definition of dihedral angle measures the angle between two
|
||||
// facets instead of facet normals.
|
||||
const double cos_tol = cos(igl::PI - tol);
|
||||
std::vector<size_t> result; // Indices into uE
|
||||
|
||||
auto is_non_manifold = [&uE2E](size_t ei) -> bool {
|
||||
return uE2E[ei].size() > 2;
|
||||
};
|
||||
|
||||
auto is_boundary = [&uE2E](size_t ei) -> bool {
|
||||
return uE2E[ei].size() == 1;
|
||||
};
|
||||
|
||||
auto opposite_vertex = [&uE, &F](size_t ei, size_t fi) -> IndexType {
|
||||
const size_t v0 = uE(ei, 0);
|
||||
const size_t v1 = uE(ei, 1);
|
||||
for (size_t i=0; i<3; i++) {
|
||||
const size_t v = F(fi, i);
|
||||
if (v != v0 && v != v1) { return v; }
|
||||
}
|
||||
throw "Input face must be topologically degenerate!";
|
||||
};
|
||||
|
||||
auto is_feature = [&V, &F, &uE, &uE2E, &opposite_vertex, num_faces](
|
||||
size_t ei, double cos_tol) -> bool {
|
||||
auto adj_faces = uE2E[ei];
|
||||
assert(adj_faces.size() == 2);
|
||||
const Vertex v0 = V.row(uE(ei, 0));
|
||||
const Vertex v1 = V.row(uE(ei, 1));
|
||||
const Vertex v2 = V.row(opposite_vertex(ei, adj_faces[0] % num_faces));
|
||||
const Vertex v3 = V.row(opposite_vertex(ei, adj_faces[1] % num_faces));
|
||||
const Point p0(v0[0], v0[1], v0[2]);
|
||||
const Point p1(v1[0], v1[1], v1[2]);
|
||||
const Point p2(v2[0], v2[1], v2[2]);
|
||||
const Point p3(v3[0], v3[1], v3[2]);
|
||||
const auto ori = CGAL::orientation(p0, p1, p2, p3);
|
||||
switch (ori) {
|
||||
case CGAL::POSITIVE:
|
||||
return CGAL::compare_dihedral_angle(p0, p1, p2, p3, cos_tol) ==
|
||||
CGAL::SMALLER;
|
||||
case CGAL::NEGATIVE:
|
||||
return CGAL::compare_dihedral_angle(p0, p1, p3, p2, cos_tol) ==
|
||||
CGAL::SMALLER;
|
||||
case CGAL::COPLANAR:
|
||||
if (!CGAL::collinear(p0, p1, p2) && !CGAL::collinear(p0, p1, p3)) {
|
||||
return CGAL::compare_dihedral_angle(p0, p1, p2, p3, cos_tol) ==
|
||||
CGAL::SMALLER;
|
||||
} else {
|
||||
throw "Dihedral angle (and feature edge) is not well defined for"
|
||||
" degenerate triangles!";
|
||||
}
|
||||
default:
|
||||
throw "Unknown CGAL orientation";
|
||||
}
|
||||
};
|
||||
|
||||
for (size_t i=0; i<num_unique_edges; i++) {
|
||||
if (is_boundary(i) || is_non_manifold(i) || is_feature(i, cos_tol)) {
|
||||
result.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
const size_t num_feature_edges = result.size();
|
||||
feature_edges.resize(num_feature_edges, 2);
|
||||
for (size_t i=0; i<num_feature_edges; i++) {
|
||||
feature_edges.row(i) = uE.row(result[i]);
|
||||
}
|
||||
}
|
||||
90
src/libigl/igl/copyleft/cgal/extract_feature.h
Normal file
90
src/libigl/igl/copyleft/cgal/extract_feature.h
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef IGL_COPYLEFT_CGAL_EXTRACT_FEATURE_H
|
||||
#define IGL_COPYLEFT_CGAL_EXTRACT_FEATURE_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Extract feature edges based on dihedral angle.
|
||||
// Here, dihedral angle is defined as the angle between surface
|
||||
// __normals__ as described in
|
||||
// http://mathworld.wolfram.com/DihedralAngle.html
|
||||
//
|
||||
// Non-manifold and boundary edges are automatically considered as
|
||||
// features.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 array of vertices.
|
||||
// F #F by 3 array of faces.
|
||||
// tol Edges with dihedral angle larger than this are considered
|
||||
// as features. Angle is measured in radian.
|
||||
//
|
||||
// Output:
|
||||
// feature_edges: #E by 2 array of edges. Each edge satisfies at
|
||||
// least one of the following criteria:
|
||||
//
|
||||
// * Edge has dihedral angle larger than tol.
|
||||
// * Edge is boundary.
|
||||
// * Edge is non-manifold (i.e. it has more than 2 adjacent
|
||||
// faces).
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedE>
|
||||
IGL_INLINE void extract_feature(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const double tol,
|
||||
Eigen::PlainObjectBase<DerivedE>& feature_edges);
|
||||
|
||||
// Inputs:
|
||||
// V #V by 3 array of vertices.
|
||||
// F #F by 3 array of faces.
|
||||
// tol Edges with dihedral angle larger than this are considered
|
||||
// as features. Angle is measured in radian.
|
||||
// E #E by 2 array of directed edges.
|
||||
// uE #uE by 2 array of undirected edges.
|
||||
// uE2E #uE list of lists mapping undirected edges to all corresponding
|
||||
// directed edges.
|
||||
//
|
||||
// Output:
|
||||
// feature_edges: #E by 2 array of edges. Each edge satisfies at
|
||||
// least one of the following criteria:
|
||||
//
|
||||
// * Edge has dihedral angle larger than tol.
|
||||
// * Edge is boundary.
|
||||
// * Edge is non-manifold (i.e. it has more than 2 adjacent
|
||||
// faces).
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedE>
|
||||
IGL_INLINE void extract_feature(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const double tol,
|
||||
const Eigen::PlainObjectBase<DerivedE>& E,
|
||||
const Eigen::PlainObjectBase<DerivedE>& uE,
|
||||
const std::vector<std::vector<typename DerivedE::Scalar> >& uE2E,
|
||||
Eigen::PlainObjectBase<DerivedE>& feature_edges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "extract_feature.cpp"
|
||||
#endif
|
||||
#endif
|
||||
82
src/libigl/igl/copyleft/cgal/fast_winding_number.cpp
Normal file
82
src/libigl/igl/copyleft/cgal/fast_winding_number.cpp
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
#include "../../fast_winding_number.h"
|
||||
#include "../../octree.h"
|
||||
#include "../../knn.h"
|
||||
#include "../../parallel_for.h"
|
||||
#include "point_areas.h"
|
||||
#include <vector>
|
||||
|
||||
namespace igl {
|
||||
namespace copyleft{
|
||||
namespace cgal{
|
||||
template <typename DerivedP, typename DerivedN, typename DerivedQ,
|
||||
typename BetaType, typename DerivedWN>
|
||||
IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
|
||||
const Eigen::MatrixBase<DerivedN>& N,
|
||||
const Eigen::MatrixBase<DerivedQ>& Q,
|
||||
const int expansion_order,
|
||||
const BetaType beta,
|
||||
Eigen::PlainObjectBase<DerivedWN>& WN
|
||||
){
|
||||
typedef typename DerivedWN::Scalar real;
|
||||
typedef typename Eigen::Matrix<real,Eigen::Dynamic,Eigen::Dynamic>
|
||||
RealMatrix;
|
||||
|
||||
std::vector<std::vector<int> > point_indices;
|
||||
Eigen::Matrix<int,Eigen::Dynamic,8> CH;
|
||||
Eigen::Matrix<real,Eigen::Dynamic,3> CN;
|
||||
Eigen::Matrix<real,Eigen::Dynamic,1> W;
|
||||
Eigen::MatrixXi I;
|
||||
Eigen::Matrix<real,Eigen::Dynamic,1> A;
|
||||
|
||||
octree(P,point_indices,CH,CN,W);
|
||||
knn(P,21,point_indices,CH,CN,W,I);
|
||||
point_areas(P,I,N,A);
|
||||
|
||||
Eigen::Matrix<real,Eigen::Dynamic,Eigen::Dynamic> EC;
|
||||
Eigen::Matrix<real,Eigen::Dynamic,3> CM;
|
||||
Eigen::Matrix<real,Eigen::Dynamic,1> R;
|
||||
|
||||
igl::fast_winding_number(P,N,A,point_indices,CH,
|
||||
expansion_order,CM,R,EC);
|
||||
igl::fast_winding_number(P,N,A,point_indices,CH,
|
||||
CM,R,EC,Q,beta,WN);
|
||||
}
|
||||
|
||||
template <typename DerivedP, typename DerivedN,
|
||||
typename DerivedQ, typename DerivedWN>
|
||||
IGL_INLINE void fast_winding_number(
|
||||
const Eigen::MatrixBase<DerivedP>& P,
|
||||
const Eigen::MatrixBase<DerivedN>& N,
|
||||
const Eigen::MatrixBase<DerivedQ>& Q,
|
||||
Eigen::PlainObjectBase<DerivedWN>& WN
|
||||
){
|
||||
fast_winding_number(P,N,Q,2,2.0,WN);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
66
src/libigl/igl/copyleft/cgal/fast_winding_number.h
Normal file
66
src/libigl/igl/copyleft/cgal/fast_winding_number.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
#ifndef IGL_COPYLEFT_CGAL_FAST_WINDING_NUMBER
|
||||
#define IGL_COPYLEFT_CGAL_FAST_WINDING_NUMBER
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
namespace igl
|
||||
{
|
||||
// Evaluate the fast winding number for point data, without known areas. The
|
||||
// areas are calculated using igl::knn and igl::copyleft::cgal::point_areas.
|
||||
//
|
||||
// This function performes the precomputation and evaluation all in one.
|
||||
// If you need to acess the precomuptation for repeated evaluations, use the
|
||||
// two functions designed for exposed precomputation, which are the first two
|
||||
// functions see in igl/fast_winding_number.h
|
||||
//
|
||||
// Inputs:
|
||||
// P #P by 3 list of point locations
|
||||
// N #P by 3 list of point normals
|
||||
// Q #Q by 3 list of query points for the winding number
|
||||
// beta This is a Barnes-Hut style accuracy term that separates near feild
|
||||
// from far field. The higher the beta, the more accurate and slower
|
||||
// the evaluation. We reccommend using a beta value of 2.
|
||||
// expansion_order the order of the taylor expansion. We support 0,1,2.
|
||||
// Outputs:
|
||||
// WN #Q by 1 list of windinng number values at each query point
|
||||
//
|
||||
template <typename DerivedP, typename DerivedN, typename DerivedQ,
|
||||
typename BetaType, typename DerivedWN>
|
||||
IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
|
||||
const Eigen::MatrixBase<DerivedN>& N,
|
||||
const Eigen::MatrixBase<DerivedQ>& Q,
|
||||
const int expansion_order,
|
||||
const BetaType beta,
|
||||
Eigen::PlainObjectBase<DerivedWN>& WN
|
||||
);
|
||||
|
||||
// Evaluate the fast winding number for point data, without known areas. The
|
||||
// areas are calculated using igl::knn and
|
||||
// igl::point_areas. This function uses the default expansion
|
||||
// order and beta (both are set to 2).
|
||||
//
|
||||
// This function performes the precomputation and evaluation all in one.
|
||||
// If you need to acess the precomuptation for repeated evaluations, use the
|
||||
// two functions designed for exposed precomputation (described above).
|
||||
|
||||
// Inputs:
|
||||
// P #P by 3 list of point locations
|
||||
// N #P by 3 list of point normals
|
||||
// Q #Q by 3 list of query points for the winding number
|
||||
// Outputs:
|
||||
// WN #Q by 1 list of windinng number values at each query point
|
||||
//
|
||||
template <typename DerivedP, typename DerivedN, typename DerivedQ,
|
||||
typename DerivedWN>
|
||||
IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
|
||||
const Eigen::MatrixBase<DerivedN>& N,
|
||||
const Eigen::MatrixBase<DerivedQ>& Q,
|
||||
Eigen::PlainObjectBase<DerivedWN>& WN
|
||||
);
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "fast_winding_number.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
123
src/libigl/igl/copyleft/cgal/half_space_box.cpp
Normal file
123
src/libigl/igl/copyleft/cgal/half_space_box.cpp
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
#include "half_space_box.h"
|
||||
#include "assign_scalar.h"
|
||||
#include <CGAL/Point_3.h>
|
||||
#include <CGAL/Vector_3.h>
|
||||
|
||||
template <typename DerivedV>
|
||||
IGL_INLINE void igl::copyleft::cgal::half_space_box(
|
||||
const CGAL::Plane_3<CGAL::Epeck> & P,
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::Matrix<CGAL::Epeck::FT,8,3> & BV,
|
||||
Eigen::Matrix<int,12,3> & BF)
|
||||
{
|
||||
typedef CGAL::Plane_3<CGAL::Epeck> Plane;
|
||||
typedef CGAL::Point_3<CGAL::Epeck> Point;
|
||||
typedef CGAL::Vector_3<CGAL::Epeck> Vector;
|
||||
typedef CGAL::Epeck::FT EScalar;
|
||||
Eigen::Matrix<typename DerivedV::Scalar,1,3> avg(0,0,0);
|
||||
for(int v = 0;v<V.rows();v++) for(int c = 0;c<V.cols();c++) avg(c) += V(v,c);
|
||||
avg /= V.rows();
|
||||
|
||||
Point o3(avg(0),avg(1),avg(2));
|
||||
Point o2 = P.projection(o3);
|
||||
Vector u;
|
||||
EScalar max_sqrd = -1;
|
||||
for(int v = 0;v<V.rows();v++)
|
||||
{
|
||||
Vector v2 = P.projection(Point(V(v,0),V(v,1),V(v,2))) - o2;
|
||||
const EScalar sqrd = v2.squared_length();
|
||||
if(max_sqrd<0 || sqrd < max_sqrd)
|
||||
{
|
||||
u = v2;
|
||||
max_sqrd = sqrd;
|
||||
}
|
||||
}
|
||||
// L1 bbd
|
||||
const EScalar bbd =
|
||||
(EScalar(V.col(0).maxCoeff())- EScalar(V.col(0).minCoeff())) +
|
||||
(EScalar(V.col(1).maxCoeff())- EScalar(V.col(1).minCoeff())) +
|
||||
(EScalar(V.col(2).maxCoeff())- EScalar(V.col(2).minCoeff()));
|
||||
Vector n = P.orthogonal_vector();
|
||||
// now we have a center o2 and a vector u to the farthest point on the plane
|
||||
std::vector<Point> vBV;vBV.reserve(8);
|
||||
Vector v = CGAL::cross_product(u,n);
|
||||
// Scale u,v,n to be longer than bbd
|
||||
const auto & longer_than = [](const EScalar min_sqr, Vector & x)
|
||||
{
|
||||
assert(x.squared_length() > 0);
|
||||
while(x.squared_length() < min_sqr)
|
||||
{
|
||||
x = 2.*x;
|
||||
}
|
||||
};
|
||||
longer_than(bbd*bbd,u);
|
||||
longer_than(bbd*bbd,v);
|
||||
longer_than(bbd*bbd,n);
|
||||
vBV.emplace_back( o2 + u + v);
|
||||
vBV.emplace_back( o2 - u + v);
|
||||
vBV.emplace_back( o2 - u - v);
|
||||
vBV.emplace_back( o2 + u - v);
|
||||
vBV.emplace_back( o2 + u + v - n);
|
||||
vBV.emplace_back( o2 - u + v - n);
|
||||
vBV.emplace_back( o2 - u - v - n);
|
||||
vBV.emplace_back( o2 + u - v - n);
|
||||
BV.resize(8,3);
|
||||
for(int b = 0;b<8;b++)
|
||||
{
|
||||
igl::copyleft::cgal::assign_scalar(vBV[b].x(),BV(b,0));
|
||||
igl::copyleft::cgal::assign_scalar(vBV[b].y(),BV(b,1));
|
||||
igl::copyleft::cgal::assign_scalar(vBV[b].z(),BV(b,2));
|
||||
}
|
||||
BF.resize(12,3);
|
||||
BF<<
|
||||
1,0,2,
|
||||
2,0,3,
|
||||
4,5,6,
|
||||
4,6,7,
|
||||
0,1,4,
|
||||
4,1,5,
|
||||
1,2,5,
|
||||
5,2,6,
|
||||
2,3,6,
|
||||
6,3,7,
|
||||
3,0,7,
|
||||
7,0,4;
|
||||
}
|
||||
|
||||
template <typename Derivedp, typename Derivedn, typename DerivedV>
|
||||
IGL_INLINE void igl::copyleft::cgal::half_space_box(
|
||||
const Eigen::MatrixBase<Derivedp> & p,
|
||||
const Eigen::MatrixBase<Derivedn> & n,
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::Matrix<CGAL::Epeck::FT,8,3> & BV,
|
||||
Eigen::Matrix<int,12,3> & BF)
|
||||
{
|
||||
typedef CGAL::Plane_3<CGAL::Epeck> Plane;
|
||||
typedef CGAL::Point_3<CGAL::Epeck> Point;
|
||||
typedef CGAL::Vector_3<CGAL::Epeck> Vector;
|
||||
Plane P(Point(p(0),p(1),p(2)),Vector(n(0),n(1),n(2)));
|
||||
return half_space_box(P,V,BV,BF);
|
||||
}
|
||||
|
||||
template <typename Derivedequ, typename DerivedV>
|
||||
IGL_INLINE void igl::copyleft::cgal::half_space_box(
|
||||
const Eigen::MatrixBase<Derivedequ> & equ,
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::Matrix<CGAL::Epeck::FT,8,3> & BV,
|
||||
Eigen::Matrix<int,12,3> & BF)
|
||||
{
|
||||
typedef CGAL::Plane_3<CGAL::Epeck> Plane;
|
||||
Plane P(equ(0),equ(1),equ(2),equ(3));
|
||||
return half_space_box(P,V,BV,BF);
|
||||
}
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::half_space_box<Eigen::Matrix<double, -1, 3, 1, -1, 3> >(CGAL::Plane_3<CGAL::Epeck> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>&, Eigen::Matrix<int, 12, 3, 0, 12, 3>&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::half_space_box<Eigen::Matrix<float, -1, 3, 1, -1, 3> >(CGAL::Plane_3<CGAL::Epeck> const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>&, Eigen::Matrix<int, 12, 3, 0, 12, 3>&);
|
||||
template void igl::copyleft::cgal::half_space_box<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 4, 1, 1, 4>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 4, 1, 1, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>&, Eigen::Matrix<int, 12, 3, 0, 12, 3>&);
|
||||
template void igl::copyleft::cgal::half_space_box<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 4, 1, 1, 4>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 4, 0, -1, 4> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 4, 1, 1, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 4, 0, -1, 4> > const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>&, Eigen::Matrix<int, 12, 3, 0, 12, 3>&);
|
||||
template void igl::copyleft::cgal::half_space_box<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 4, 1, 1, 4>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 4, 1, 1, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>&, Eigen::Matrix<int, 12, 3, 0, 12, 3>&);
|
||||
template void igl::copyleft::cgal::half_space_box<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>&, Eigen::Matrix<int, 12, 3, 0, 12, 3>&);
|
||||
#endif
|
||||
63
src/libigl/igl/copyleft/cgal/half_space_box.h
Normal file
63
src/libigl/igl/copyleft/cgal/half_space_box.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#ifndef IGL_COPYLEFT_CGAL_HALF_SPACE_BOX_H
|
||||
#define IGL_COPYLEFT_CGAL_HALF_SPACE_BOX_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Plane_3.h>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Construct a mesh of box (BV,BF) so that it contains the intersection of
|
||||
// the half-space under the plane (P) and the bounding box of V, and does not
|
||||
// contain any of the half-space above (P).
|
||||
//
|
||||
// Inputs:
|
||||
// P plane so that normal points away from half-space
|
||||
// V #V by 3 list of vertex positions
|
||||
// Outputs:
|
||||
// BV #BV by 3 list of box vertex positions
|
||||
// BF #BF b3 list of box triangle indices into BV
|
||||
template <typename DerivedV>
|
||||
IGL_INLINE void half_space_box(
|
||||
const CGAL::Plane_3<CGAL::Epeck> & P,
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::Matrix<CGAL::Epeck::FT,8,3> & BV,
|
||||
Eigen::Matrix<int,12,3> & BF);
|
||||
// Inputs:
|
||||
// p 3d point on plane
|
||||
// n 3d vector of normal of plane pointing away from inside
|
||||
// V #V by 3 list of vertex positions
|
||||
// Outputs:
|
||||
// BV #BV by 3 list of box vertex positions
|
||||
// BF #BF b3 list of box triangle indices into BV
|
||||
template <typename Derivedp, typename Derivedn, typename DerivedV>
|
||||
IGL_INLINE void half_space_box(
|
||||
const Eigen::MatrixBase<Derivedp> & p,
|
||||
const Eigen::MatrixBase<Derivedn> & n,
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::Matrix<CGAL::Epeck::FT,8,3> & BV,
|
||||
Eigen::Matrix<int,12,3> & BF);
|
||||
// Inputs:
|
||||
// equ plane equation: a*x+b*y+c*z + d = 0
|
||||
// V #V by 3 list of vertex positions
|
||||
// Outputs:
|
||||
// BV #BV by 3 list of box vertex positions
|
||||
// BF #BF b3 list of box triangle indices into BV
|
||||
template <typename Derivedequ, typename DerivedV>
|
||||
IGL_INLINE void half_space_box(
|
||||
const Eigen::MatrixBase<Derivedequ> & equ,
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
Eigen::Matrix<CGAL::Epeck::FT,8,3> & BV,
|
||||
Eigen::Matrix<int,12,3> & BF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "half_space_box.cpp"
|
||||
#endif
|
||||
#endif
|
||||
39
src/libigl/igl/copyleft/cgal/hausdorff.cpp
Normal file
39
src/libigl/igl/copyleft/cgal/hausdorff.cpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#include "hausdorff.h"
|
||||
#include "../../hausdorff.h"
|
||||
#include <functional>
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename Kernel,
|
||||
typename Scalar>
|
||||
IGL_INLINE void igl::copyleft::cgal::hausdorff(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const CGAL::AABB_tree<
|
||||
CGAL::AABB_traits<Kernel,
|
||||
CGAL::AABB_triangle_primitive<Kernel,
|
||||
typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
|
||||
>
|
||||
>
|
||||
> & treeB,
|
||||
const std::vector<CGAL::Triangle_3<Kernel> > & /*TB*/,
|
||||
Scalar & l,
|
||||
Scalar & u)
|
||||
{
|
||||
// Not sure why using `auto` here doesn't work with the `hausdorff` function
|
||||
// parameter but explicitly naming the type does...
|
||||
const std::function<double(const double &,const double &,const double &)>
|
||||
dist_to_B = [&treeB](
|
||||
const double & x, const double & y, const double & z)->double
|
||||
{
|
||||
CGAL::Point_3<Kernel> query(x,y,z);
|
||||
typename CGAL::AABB_tree<
|
||||
CGAL::AABB_traits<Kernel,
|
||||
CGAL::AABB_triangle_primitive<Kernel,
|
||||
typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
|
||||
>
|
||||
>
|
||||
>::Point_and_primitive_id pp = treeB.closest_point_and_primitive(query);
|
||||
return std::sqrt((query-pp.first).squared_length());
|
||||
};
|
||||
return igl::hausdorff(V,dist_to_B,l,u);
|
||||
}
|
||||
62
src/libigl/igl/copyleft/cgal/hausdorff.h
Normal file
62
src/libigl/igl/copyleft/cgal/hausdorff.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_HAUSDORFF_H
|
||||
#define IGL_COPYLEFT_CGAL_HAUSDORFF_H
|
||||
#include "../../igl_inline.h"
|
||||
|
||||
#include <Eigen/Dense>
|
||||
#include "CGAL_includes.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Compute lower and upper bounds (l,u) on the Hausdorff distance between a triangle
|
||||
// (V) and a pointset (e.g., mesh, triangle soup) given by a distance function
|
||||
// handle (dist_to_B).
|
||||
//
|
||||
// Inputs:
|
||||
// V 3 by 3 list of corner positions so that V.row(i) is the position of the
|
||||
// ith corner
|
||||
// treeB CGAL's AABB tree containing triangle soup (VB,FB)
|
||||
// TB list of CGAL triangles in order of FB (for determining which was found
|
||||
// in computation)
|
||||
// Outputs:
|
||||
// l lower bound on Hausdorff distance
|
||||
// u upper bound on Hausdorff distance
|
||||
//
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename Kernel,
|
||||
typename Scalar>
|
||||
IGL_INLINE void hausdorff(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const CGAL::AABB_tree<
|
||||
CGAL::AABB_traits<Kernel,
|
||||
CGAL::AABB_triangle_primitive<Kernel,
|
||||
typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
|
||||
>
|
||||
>
|
||||
> & treeB,
|
||||
const std::vector<CGAL::Triangle_3<Kernel> > & TB,
|
||||
Scalar & l,
|
||||
Scalar & u);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "hausdorff.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
39
src/libigl/igl/copyleft/cgal/incircle.cpp
Normal file
39
src/libigl/igl/copyleft/cgal/incircle.cpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "incircle.h"
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
template<typename Scalar>
|
||||
IGL_INLINE short igl::copyleft::cgal::incircle(
|
||||
const Scalar pa[2],
|
||||
const Scalar pb[2],
|
||||
const Scalar pc[2],
|
||||
const Scalar pd[2])
|
||||
{
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Epeck;
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Epick;
|
||||
typedef typename std::conditional<std::is_same<Scalar, Epeck::FT>::value,
|
||||
Epeck, Epick>::type Kernel;
|
||||
|
||||
switch(CGAL::side_of_oriented_circle(
|
||||
typename Kernel::Point_2(pa[0], pa[1]),
|
||||
typename Kernel::Point_2(pb[0], pb[1]),
|
||||
typename Kernel::Point_2(pc[0], pc[1]),
|
||||
typename Kernel::Point_2(pd[0], pd[1]))) {
|
||||
case CGAL::ON_POSITIVE_SIDE:
|
||||
return 1;
|
||||
case CGAL::ON_NEGATIVE_SIDE:
|
||||
return -1;
|
||||
case CGAL::ON_ORIENTED_BOUNDARY:
|
||||
return 0;
|
||||
default:
|
||||
throw "Invalid incircle result";
|
||||
}
|
||||
}
|
||||
39
src/libigl/igl/copyleft/cgal/incircle.h
Normal file
39
src/libigl/igl/copyleft/cgal/incircle.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef IGL_COPYLEFT_CGAL_INCIRCLE_H
|
||||
#define IGL_COPYLEFT_CGAL_INCIRCLE_H
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Inputs:
|
||||
// pa,pb,pc,pd 2D points.
|
||||
// Output:
|
||||
// 1 if pd is inside of the oriented circle formed by pa,pb,pc.
|
||||
// 0 if pd is co-circular with pa,pb,pc.
|
||||
// -1 if pd is outside of the oriented circle formed by pa,pb,pc.
|
||||
template <typename Scalar>
|
||||
IGL_INLINE short incircle(
|
||||
const Scalar pa[2],
|
||||
const Scalar pb[2],
|
||||
const Scalar pc[2],
|
||||
const Scalar pd[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "incircle.cpp"
|
||||
#endif
|
||||
#endif
|
||||
68
src/libigl/igl/copyleft/cgal/insert_into_cdt.cpp
Normal file
68
src/libigl/igl/copyleft/cgal/insert_into_cdt.cpp
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "insert_into_cdt.h"
|
||||
#include <CGAL/Point_3.h>
|
||||
#include <CGAL/Segment_3.h>
|
||||
#include <CGAL/Triangle_3.h>
|
||||
|
||||
template <typename Kernel>
|
||||
IGL_INLINE void igl::copyleft::cgal::insert_into_cdt(
|
||||
const CGAL::Object & obj,
|
||||
const CGAL::Plane_3<Kernel> & P,
|
||||
CGAL::Constrained_triangulation_plus_2<
|
||||
CGAL::Constrained_Delaunay_triangulation_2<
|
||||
Kernel,
|
||||
CGAL::Triangulation_data_structure_2<
|
||||
CGAL::Triangulation_vertex_base_2<Kernel>,
|
||||
CGAL::Constrained_triangulation_face_base_2< Kernel>
|
||||
>,
|
||||
CGAL::Exact_intersections_tag
|
||||
>
|
||||
>
|
||||
& cdt)
|
||||
{
|
||||
typedef CGAL::Point_3<Kernel> Point_3;
|
||||
typedef CGAL::Segment_3<Kernel> Segment_3;
|
||||
typedef CGAL::Triangle_3<Kernel> Triangle_3;
|
||||
|
||||
if(const Segment_3 *iseg = CGAL::object_cast<Segment_3 >(&obj))
|
||||
{
|
||||
// Add segment constraint
|
||||
cdt.insert_constraint( P.to_2d(iseg->vertex(0)),P.to_2d(iseg->vertex(1)));
|
||||
}else if(const Point_3 *ipoint = CGAL::object_cast<Point_3 >(&obj))
|
||||
{
|
||||
// Add point
|
||||
cdt.insert(P.to_2d(*ipoint));
|
||||
} else if(const Triangle_3 *itri = CGAL::object_cast<Triangle_3 >(&obj))
|
||||
{
|
||||
// Add 3 segment constraints
|
||||
cdt.insert_constraint( P.to_2d(itri->vertex(0)),P.to_2d(itri->vertex(1)));
|
||||
cdt.insert_constraint( P.to_2d(itri->vertex(1)),P.to_2d(itri->vertex(2)));
|
||||
cdt.insert_constraint( P.to_2d(itri->vertex(2)),P.to_2d(itri->vertex(0)));
|
||||
} else if(const std::vector<Point_3 > *polyp =
|
||||
CGAL::object_cast< std::vector<Point_3 > >(&obj))
|
||||
{
|
||||
const std::vector<Point_3 > & poly = *polyp;
|
||||
const size_t m = poly.size();
|
||||
assert(m>=2);
|
||||
for(size_t p = 0;p<m;p++)
|
||||
{
|
||||
const size_t np = (p+1)%m;
|
||||
cdt.insert_constraint(P.to_2d(poly[p]),P.to_2d(poly[np]));
|
||||
}
|
||||
}else {
|
||||
throw std::runtime_error("Unknown intersection object!");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
template void igl::copyleft::cgal::insert_into_cdt<CGAL::Epick>(CGAL::Object const&, CGAL::Plane_3<CGAL::Epick> const&, CGAL::Constrained_triangulation_plus_2<CGAL::Constrained_Delaunay_triangulation_2<CGAL::Epick, CGAL::Triangulation_data_structure_2<CGAL::Triangulation_vertex_base_2<CGAL::Epick, CGAL::Triangulation_ds_vertex_base_2<void> >, CGAL::Constrained_triangulation_face_base_2<CGAL::Epick, CGAL::Triangulation_face_base_2<CGAL::Epick, CGAL::Triangulation_ds_face_base_2<void> > > >, CGAL::Exact_intersections_tag> >&);
|
||||
template void igl::copyleft::cgal::insert_into_cdt<CGAL::Epeck>(CGAL::Object const&, CGAL::Plane_3<CGAL::Epeck> const&, CGAL::Constrained_triangulation_plus_2<CGAL::Constrained_Delaunay_triangulation_2<CGAL::Epeck, CGAL::Triangulation_data_structure_2<CGAL::Triangulation_vertex_base_2<CGAL::Epeck, CGAL::Triangulation_ds_vertex_base_2<void> >, CGAL::Constrained_triangulation_face_base_2<CGAL::Epeck, CGAL::Triangulation_face_base_2<CGAL::Epeck, CGAL::Triangulation_ds_face_base_2<void> > > >, CGAL::Exact_intersections_tag> >&);
|
||||
#endif
|
||||
60
src/libigl/igl/copyleft/cgal/insert_into_cdt.h
Normal file
60
src/libigl/igl/copyleft/cgal/insert_into_cdt.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_INSERT_INTO_CDT_H
|
||||
#define IGL_COPYLEFT_CGAL_INSERT_INTO_CDT_H
|
||||
#include "../../igl_inline.h"
|
||||
|
||||
#include <CGAL/double.h> // Workaround https://github.com/CGAL/cgal/issues/2182 with CGAL 4.10-1
|
||||
#include <CGAL/Plane_3.h>
|
||||
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
|
||||
#include <CGAL/Constrained_triangulation_plus_2.h>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Given a current 2D constrained Delaunay triangulation (cdt), insert a
|
||||
// 3D "object" (e.g., resulting from intersecting two triangles) into the
|
||||
// cdt, by projecting it via the given plane (P) and adding appropriate
|
||||
// constraints.
|
||||
//
|
||||
// Inputs:
|
||||
// obj CGAL::Object representing a vertex, segment, or (convex)
|
||||
// polygon. All vertices should lie on the plane P. If not, then this
|
||||
// adds the _projection_ of this object to the cdt and that might not
|
||||
// be what you wanted to do.
|
||||
// P plane obj lies on and upon which the cdt is being performed
|
||||
// cdt current CDT, see output
|
||||
// Outputs:
|
||||
// cdt CDT updated to contain constraints for the given object
|
||||
//
|
||||
template <typename Kernel>
|
||||
IGL_INLINE void insert_into_cdt(
|
||||
const CGAL::Object & obj,
|
||||
const CGAL::Plane_3<Kernel> & P,
|
||||
CGAL::Constrained_triangulation_plus_2<
|
||||
CGAL::Constrained_Delaunay_triangulation_2<
|
||||
Kernel,
|
||||
CGAL::Triangulation_data_structure_2<
|
||||
CGAL::Triangulation_vertex_base_2<Kernel>,
|
||||
CGAL::Constrained_triangulation_face_base_2< Kernel>
|
||||
>,
|
||||
CGAL::Exact_intersections_tag
|
||||
>
|
||||
>
|
||||
& cdt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "insert_into_cdt.cpp"
|
||||
#endif
|
||||
#endif
|
||||
41
src/libigl/igl/copyleft/cgal/insphere.cpp
Normal file
41
src/libigl/igl/copyleft/cgal/insphere.cpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "insphere.h"
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
template<typename Scalar>
|
||||
IGL_INLINE short igl::copyleft::cgal::insphere(
|
||||
const Scalar pa[3],
|
||||
const Scalar pb[3],
|
||||
const Scalar pc[3],
|
||||
const Scalar pd[3],
|
||||
const Scalar pe[3])
|
||||
{
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Epeck;
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Epick;
|
||||
typedef typename std::conditional<std::is_same<Scalar, Epeck::FT>::value,
|
||||
Epeck, Epick>::type Kernel;
|
||||
|
||||
switch(CGAL::side_of_oriented_sphere(
|
||||
typename Kernel::Point_3(pa[0], pa[1], pa[2]),
|
||||
typename Kernel::Point_3(pb[0], pb[1], pb[2]),
|
||||
typename Kernel::Point_3(pc[0], pc[1], pc[2]),
|
||||
typename Kernel::Point_3(pd[0], pd[1], pd[2]),
|
||||
typename Kernel::Point_3(pe[0], pe[1], pe[2]))) {
|
||||
case CGAL::ON_POSITIVE_SIDE:
|
||||
return 1;
|
||||
case CGAL::ON_NEGATIVE_SIDE:
|
||||
return -1;
|
||||
case CGAL::ON_ORIENTED_BOUNDARY:
|
||||
return 0;
|
||||
default:
|
||||
throw "Invalid incircle result";
|
||||
}
|
||||
}
|
||||
40
src/libigl/igl/copyleft/cgal/insphere.h
Normal file
40
src/libigl/igl/copyleft/cgal/insphere.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef IGL_COPYLEFT_CGAL_INSPHERE_H
|
||||
#define IGL_COPYLEFT_CGAL_INSPHERE_H
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Inputs:
|
||||
// pa,pb,pc,pd,pe 3D points.
|
||||
// Output:
|
||||
// 1 if pe is inside of the oriented sphere formed by pa,pb,pc,pd.
|
||||
// 0 if pe is co-spherical with pa,pb,pc,pd.
|
||||
// -1 if pe is outside of the oriented sphere formed by pa,pb,pc,pd.
|
||||
template <typename Scalar>
|
||||
IGL_INLINE short insphere(
|
||||
const Scalar pa[3],
|
||||
const Scalar pb[3],
|
||||
const Scalar pc[3],
|
||||
const Scalar pd[3],
|
||||
const Scalar pe[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "insphere.cpp"
|
||||
#endif
|
||||
#endif
|
||||
289
src/libigl/igl/copyleft/cgal/intersect_other.cpp
Normal file
289
src/libigl/igl/copyleft/cgal/intersect_other.cpp
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "intersect_other.h"
|
||||
#include "CGAL_includes.hpp"
|
||||
#include "mesh_to_cgal_triangle_list.h"
|
||||
#include "remesh_intersections.h"
|
||||
#include "../../slice_mask.h"
|
||||
#include "../../remove_unreferenced.h"
|
||||
|
||||
#ifndef IGL_FIRST_HIT_EXCEPTION
|
||||
#define IGL_FIRST_HIT_EXCEPTION 10
|
||||
#endif
|
||||
|
||||
// Un-exposed helper functions
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
template <typename DerivedF>
|
||||
static IGL_INLINE void push_result(
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
const int f,
|
||||
const int f_other,
|
||||
const CGAL::Object & result,
|
||||
std::map<
|
||||
typename DerivedF::Index,
|
||||
std::vector<std::pair<typename DerivedF::Index, CGAL::Object> > > &
|
||||
offending)
|
||||
//std::map<
|
||||
// std::pair<typename DerivedF::Index,typename DerivedF::Index>,
|
||||
// std::vector<typename DerivedF::Index> > & edge2faces)
|
||||
{
|
||||
typedef typename DerivedF::Index Index;
|
||||
typedef std::pair<Index,Index> EMK;
|
||||
if(offending.count(f) == 0)
|
||||
{
|
||||
// first time marking, initialize with new id and empty list
|
||||
offending[f] = {};
|
||||
for(Index e = 0; e<3;e++)
|
||||
{
|
||||
// append face to edge's list
|
||||
Index i = F(f,(e+1)%3) < F(f,(e+2)%3) ? F(f,(e+1)%3) : F(f,(e+2)%3);
|
||||
Index j = F(f,(e+1)%3) < F(f,(e+2)%3) ? F(f,(e+2)%3) : F(f,(e+1)%3);
|
||||
//edge2faces[EMK(i,j)].push_back(f);
|
||||
}
|
||||
}
|
||||
offending[f].push_back({f_other,result});
|
||||
}
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedIF,
|
||||
typename DerivedVVAB,
|
||||
typename DerivedFFAB,
|
||||
typename DerivedJAB,
|
||||
typename DerivedIMAB>
|
||||
static IGL_INLINE bool intersect_other_helper(
|
||||
const Eigen::PlainObjectBase<DerivedVA> & VA,
|
||||
const Eigen::PlainObjectBase<DerivedFA> & FA,
|
||||
const Eigen::PlainObjectBase<DerivedVB> & VB,
|
||||
const Eigen::PlainObjectBase<DerivedFB> & FB,
|
||||
const RemeshSelfIntersectionsParam & params,
|
||||
Eigen::PlainObjectBase<DerivedIF> & IF,
|
||||
Eigen::PlainObjectBase<DerivedVVAB> & VVAB,
|
||||
Eigen::PlainObjectBase<DerivedFFAB> & FFAB,
|
||||
Eigen::PlainObjectBase<DerivedJAB> & JAB,
|
||||
Eigen::PlainObjectBase<DerivedIMAB> & IMAB)
|
||||
{
|
||||
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
|
||||
typedef typename DerivedFA::Index Index;
|
||||
// 3D Primitives
|
||||
typedef CGAL::Point_3<Kernel> Point_3;
|
||||
typedef CGAL::Segment_3<Kernel> Segment_3;
|
||||
typedef CGAL::Triangle_3<Kernel> Triangle_3;
|
||||
typedef CGAL::Plane_3<Kernel> Plane_3;
|
||||
typedef CGAL::Tetrahedron_3<Kernel> Tetrahedron_3;
|
||||
// 2D Primitives
|
||||
typedef CGAL::Point_2<Kernel> Point_2;
|
||||
typedef CGAL::Segment_2<Kernel> Segment_2;
|
||||
typedef CGAL::Triangle_2<Kernel> Triangle_2;
|
||||
// 2D Constrained Delaunay Triangulation types
|
||||
typedef CGAL::Triangulation_vertex_base_2<Kernel> TVB_2;
|
||||
typedef CGAL::Constrained_triangulation_face_base_2<Kernel> CTAB_2;
|
||||
typedef CGAL::Triangulation_data_structure_2<TVB_2,CTAB_2> TDS_2;
|
||||
typedef CGAL::Exact_intersections_tag Itag;
|
||||
// Axis-align boxes for all-pairs self-intersection detection
|
||||
typedef std::vector<Triangle_3> Triangles;
|
||||
typedef typename Triangles::iterator TrianglesIterator;
|
||||
typedef typename Triangles::const_iterator TrianglesConstIterator;
|
||||
typedef
|
||||
CGAL::Box_intersection_d::Box_with_handle_d<double,3,TrianglesIterator>
|
||||
Box;
|
||||
typedef
|
||||
std::map<Index,std::vector<std::pair<Index,CGAL::Object> > >
|
||||
OffendingMap;
|
||||
typedef std::map<std::pair<Index,Index>,std::vector<Index> > EdgeMap;
|
||||
typedef std::pair<Index,Index> EMK;
|
||||
|
||||
Triangles TA,TB;
|
||||
// Compute and process self intersections
|
||||
mesh_to_cgal_triangle_list(VA,FA,TA);
|
||||
mesh_to_cgal_triangle_list(VB,FB,TB);
|
||||
// http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Box_intersection_d/Chapter_main.html#Section_63.5
|
||||
// Create the corresponding vector of bounding boxes
|
||||
std::vector<Box> A_boxes,B_boxes;
|
||||
const auto box_up = [](Triangles & T, std::vector<Box> & boxes) -> void
|
||||
{
|
||||
boxes.reserve(T.size());
|
||||
for (
|
||||
TrianglesIterator tit = T.begin();
|
||||
tit != T.end();
|
||||
++tit)
|
||||
{
|
||||
boxes.push_back(Box(tit->bbox(), tit));
|
||||
}
|
||||
};
|
||||
box_up(TA,A_boxes);
|
||||
box_up(TB,B_boxes);
|
||||
OffendingMap offendingA,offendingB;
|
||||
//EdgeMap edge2facesA,edge2facesB;
|
||||
|
||||
std::list<int> lIF;
|
||||
const auto cb = [&](const Box &a, const Box &b) -> void
|
||||
{
|
||||
using namespace std;
|
||||
// index in F and T
|
||||
int fa = a.handle()-TA.begin();
|
||||
int fb = b.handle()-TB.begin();
|
||||
const Triangle_3 & A = *a.handle();
|
||||
const Triangle_3 & B = *b.handle();
|
||||
if(CGAL::do_intersect(A,B))
|
||||
{
|
||||
// There was an intersection
|
||||
lIF.push_back(fa);
|
||||
lIF.push_back(fb);
|
||||
if(params.first_only)
|
||||
{
|
||||
throw IGL_FIRST_HIT_EXCEPTION;
|
||||
}
|
||||
if(!params.detect_only)
|
||||
{
|
||||
CGAL::Object result = CGAL::intersection(A,B);
|
||||
|
||||
push_result(FA,fa,fb,result,offendingA);
|
||||
push_result(FB,fb,fa,result,offendingB);
|
||||
}
|
||||
}
|
||||
};
|
||||
try{
|
||||
CGAL::box_intersection_d(
|
||||
A_boxes.begin(), A_boxes.end(),
|
||||
B_boxes.begin(), B_boxes.end(),
|
||||
cb);
|
||||
}catch(int e)
|
||||
{
|
||||
// Rethrow if not FIRST_HIT_EXCEPTION
|
||||
if(e != IGL_FIRST_HIT_EXCEPTION)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
// Otherwise just fall through
|
||||
}
|
||||
|
||||
// Convert lIF to Eigen matrix
|
||||
assert(lIF.size()%2 == 0);
|
||||
IF.resize(lIF.size()/2,2);
|
||||
{
|
||||
int i=0;
|
||||
for(
|
||||
list<int>::const_iterator ifit = lIF.begin();
|
||||
ifit!=lIF.end();
|
||||
)
|
||||
{
|
||||
IF(i,0) = (*ifit);
|
||||
ifit++;
|
||||
IF(i,1) = (*ifit);
|
||||
ifit++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if(!params.detect_only)
|
||||
{
|
||||
// Obsolete, now remesh_intersections expects a single mesh
|
||||
// remesh_intersections(VA,FA,TA,offendingA,VVA,FFA,JA,IMA);
|
||||
// remesh_intersections(VB,FB,TB,offendingB,VVB,FFB,JB,IMB);
|
||||
// Combine mesh and offending maps
|
||||
DerivedVA VAB(VA.rows()+VB.rows(),3);
|
||||
VAB<<VA,VB;
|
||||
DerivedFA FAB(FA.rows()+FB.rows(),3);
|
||||
FAB<<FA,(FB.array()+VA.rows());
|
||||
Triangles TAB;
|
||||
TAB.reserve(TA.size()+TB.size());
|
||||
TAB.insert(TAB.end(),TA.begin(),TA.end());
|
||||
TAB.insert(TAB.end(),TB.begin(),TB.end());
|
||||
OffendingMap offending;
|
||||
//offending.reserve(offendingA.size() + offendingB.size());
|
||||
for (const auto itr : offendingA)
|
||||
{
|
||||
// Remap offenders in FB to FAB
|
||||
auto offenders = itr.second;
|
||||
for(auto & offender : offenders)
|
||||
{
|
||||
offender.first += FA.rows();
|
||||
}
|
||||
offending[itr.first] = offenders;
|
||||
}
|
||||
for (const auto itr : offendingB)
|
||||
{
|
||||
// Store offenders for FB according to place in FAB
|
||||
offending[FA.rows() + itr.first] = itr.second;
|
||||
}
|
||||
|
||||
remesh_intersections(
|
||||
VAB,FAB,TAB,offending,params.stitch_all,VVAB,FFAB,JAB,IMAB);
|
||||
}
|
||||
|
||||
return IF.rows() > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedIF,
|
||||
typename DerivedVVAB,
|
||||
typename DerivedFFAB,
|
||||
typename DerivedJAB,
|
||||
typename DerivedIMAB>
|
||||
IGL_INLINE bool igl::copyleft::cgal::intersect_other(
|
||||
const Eigen::PlainObjectBase<DerivedVA> & VA,
|
||||
const Eigen::PlainObjectBase<DerivedFA> & FA,
|
||||
const Eigen::PlainObjectBase<DerivedVB> & VB,
|
||||
const Eigen::PlainObjectBase<DerivedFB> & FB,
|
||||
const RemeshSelfIntersectionsParam & params,
|
||||
Eigen::PlainObjectBase<DerivedIF> & IF,
|
||||
Eigen::PlainObjectBase<DerivedVVAB> & VVAB,
|
||||
Eigen::PlainObjectBase<DerivedFFAB> & FFAB,
|
||||
Eigen::PlainObjectBase<DerivedJAB> & JAB,
|
||||
Eigen::PlainObjectBase<DerivedIMAB> & IMAB)
|
||||
{
|
||||
if(params.detect_only)
|
||||
{
|
||||
return intersect_other_helper<CGAL::Epick>
|
||||
(VA,FA,VB,FB,params,IF,VVAB,FFAB,JAB,IMAB);
|
||||
}else
|
||||
{
|
||||
return intersect_other_helper<CGAL::Epeck>
|
||||
(VA,FA,VB,FB,params,IF,VVAB,FFAB,JAB,IMAB);
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE bool igl::copyleft::cgal::intersect_other(
|
||||
const Eigen::MatrixXd & VA,
|
||||
const Eigen::MatrixXi & FA,
|
||||
const Eigen::MatrixXd & VB,
|
||||
const Eigen::MatrixXi & FB,
|
||||
const bool first_only,
|
||||
Eigen::MatrixXi & IF)
|
||||
{
|
||||
Eigen::MatrixXd VVAB;
|
||||
Eigen::MatrixXi FFAB;
|
||||
Eigen::VectorXi JAB,IMAB;
|
||||
return intersect_other(
|
||||
VA,FA,VB,FB,{true,first_only},IF,VVAB,FFAB,JAB,IMAB);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template bool igl::copyleft::cgal::intersect_other<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::intersect_other<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
91
src/libigl/igl/copyleft/cgal/intersect_other.h
Normal file
91
src/libigl/igl/copyleft/cgal/intersect_other.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_INTERSECT_OTHER_H
|
||||
#define IGL_COPYLEFT_CGAL_INTERSECT_OTHER_H
|
||||
#include "../../igl_inline.h"
|
||||
#include "RemeshSelfIntersectionsParam.h"
|
||||
|
||||
#include <Eigen/Dense>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// INTERSECT_OTHER Given a triangle mesh (VA,FA) and another mesh (VB,FB)
|
||||
// find all pairs of intersecting faces. Note that self-intersections are
|
||||
// ignored.
|
||||
//
|
||||
// Inputs:
|
||||
// VA #V by 3 list of vertex positions
|
||||
// FA #F by 3 list of triangle indices into VA
|
||||
// VB #V by 3 list of vertex positions
|
||||
// FB #F by 3 list of triangle indices into VB
|
||||
// params whether to detect only and then whether to only find first
|
||||
// intersection
|
||||
// Outputs:
|
||||
// IF #intersecting face pairs by 2 list of intersecting face pairs,
|
||||
// indexing FA and FB
|
||||
// VVAB #VVAB by 3 list of vertex positions
|
||||
// FFAB #FFAB by 3 list of triangle indices into VVA
|
||||
// JAB #FFAB list of indices into [FA;FB] denoting birth triangle
|
||||
// IMAB #VVAB list of indices stitching duplicates (resulting from
|
||||
// mesh intersections) together
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedIF,
|
||||
typename DerivedVVAB,
|
||||
typename DerivedFFAB,
|
||||
typename DerivedJAB,
|
||||
typename DerivedIMAB>
|
||||
IGL_INLINE bool intersect_other(
|
||||
const Eigen::PlainObjectBase<DerivedVA> & VA,
|
||||
const Eigen::PlainObjectBase<DerivedFA> & FA,
|
||||
const Eigen::PlainObjectBase<DerivedVB> & VB,
|
||||
const Eigen::PlainObjectBase<DerivedFB> & FB,
|
||||
const RemeshSelfIntersectionsParam & params,
|
||||
Eigen::PlainObjectBase<DerivedIF> & IF,
|
||||
Eigen::PlainObjectBase<DerivedVVAB> & VVAB,
|
||||
Eigen::PlainObjectBase<DerivedFFAB> & FFAB,
|
||||
Eigen::PlainObjectBase<DerivedJAB> & JAB,
|
||||
Eigen::PlainObjectBase<DerivedIMAB> & IMAB);
|
||||
// Legacy wrapper for detect only using common types.
|
||||
//
|
||||
// Inputs:
|
||||
// VA #V by 3 list of vertex positions
|
||||
// FA #F by 3 list of triangle indices into VA
|
||||
// VB #V by 3 list of vertex positions
|
||||
// FB #F by 3 list of triangle indices into VB
|
||||
// first_only whether to only detect the first intersection.
|
||||
// Outputs:
|
||||
// IF #intersecting face pairs by 2 list of intersecting face pairs,
|
||||
// indexing FA and FB
|
||||
// Returns true if any intersections were found
|
||||
//
|
||||
// See also: remesh_self_intersections
|
||||
IGL_INLINE bool intersect_other(
|
||||
const Eigen::MatrixXd & VA,
|
||||
const Eigen::MatrixXi & FA,
|
||||
const Eigen::MatrixXd & VB,
|
||||
const Eigen::MatrixXi & FB,
|
||||
const bool first_only,
|
||||
Eigen::MatrixXi & IF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "intersect_other.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
88
src/libigl/igl/copyleft/cgal/intersect_with_half_space.cpp
Normal file
88
src/libigl/igl/copyleft/cgal/intersect_with_half_space.cpp
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
#include "intersect_with_half_space.h"
|
||||
#include "mesh_boolean.h"
|
||||
#include "half_space_box.h"
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename Derivedp,
|
||||
typename Derivedn,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool igl::copyleft::cgal::intersect_with_half_space(
|
||||
const Eigen::MatrixBase<DerivedV > & V,
|
||||
const Eigen::MatrixBase<DerivedF > & F,
|
||||
const Eigen::MatrixBase<Derivedp > & p,
|
||||
const Eigen::MatrixBase<Derivedn > & n,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J)
|
||||
{
|
||||
typedef CGAL::Plane_3<CGAL::Epeck> Plane;
|
||||
typedef CGAL::Point_3<CGAL::Epeck> Point;
|
||||
typedef CGAL::Vector_3<CGAL::Epeck> Vector;
|
||||
Plane P(Point(p(0),p(1),p(2)),Vector(n(0),n(1),n(2)));
|
||||
return intersect_with_half_space(V,F,P,VC,FC,J);
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename Derivedequ,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool igl::copyleft::cgal::intersect_with_half_space(
|
||||
const Eigen::MatrixBase<DerivedV > & V,
|
||||
const Eigen::MatrixBase<DerivedF > & F,
|
||||
const Eigen::MatrixBase<Derivedequ > & equ,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J)
|
||||
{
|
||||
typedef CGAL::Plane_3<CGAL::Epeck> Plane;
|
||||
Plane P(equ(0),equ(1),equ(2),equ(3));
|
||||
return intersect_with_half_space(V,F,P,VC,FC,J);
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool igl::copyleft::cgal::intersect_with_half_space(
|
||||
const Eigen::MatrixBase<DerivedV > & V,
|
||||
const Eigen::MatrixBase<DerivedF > & F,
|
||||
const CGAL::Plane_3<CGAL::Epeck> & P,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J)
|
||||
{
|
||||
Eigen::Matrix<CGAL::Epeck::FT,8,3> BV;
|
||||
Eigen::Matrix<int,12,3> BF;
|
||||
half_space_box(P,V,BV,BF);
|
||||
// Disturbingly, (BV,BF) must be first argument
|
||||
const bool ret = mesh_boolean(BV,BF,V,F,MESH_BOOLEAN_TYPE_INTERSECT,VC,FC,J);
|
||||
// But now J is wrong...
|
||||
std::for_each(
|
||||
J.data(),
|
||||
J.data()+J.size(),
|
||||
[&BF,&F](typename DerivedJ::Scalar & j)
|
||||
{j = (j<BF.rows()?F.rows()+j:j-BF.rows());}
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template bool igl::copyleft::cgal::intersect_with_half_space<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template bool igl::copyleft::cgal::intersect_with_half_space<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::CwiseUnaryOp<Eigen::internal::scalar_opposite_op<double>, Eigen::Matrix<double, 1, 3, 1, 1, 3> const>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::CwiseUnaryOp<Eigen::internal::scalar_opposite_op<double>, Eigen::Matrix<double, 1, 3, 1, 1, 3> const> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template bool igl::copyleft::cgal::intersect_with_half_space<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template bool igl::copyleft::cgal::intersect_with_half_space<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::CwiseUnaryOp<Eigen::internal::scalar_opposite_op<float>, Eigen::Matrix<float, 1, 3, 1, 1, 3> const>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::CwiseUnaryOp<Eigen::internal::scalar_opposite_op<float>, Eigen::Matrix<float, 1, 3, 1, 1, 3> const> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
96
src/libigl/igl/copyleft/cgal/intersect_with_half_space.h
Normal file
96
src/libigl/igl/copyleft/cgal/intersect_with_half_space.h
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
#ifndef IGL_COPYLEFT_CGAL_INTERSECT_WITH_HALF_SPACE_H
|
||||
#define IGL_COPYLEFT_CGAL_INTERSECT_WITH_HALF_SPACE_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Plane_3.h>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Intersect a PWN mesh with a half-space. Point on plane, normal pointing
|
||||
// outward.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of mesh vertex positions
|
||||
// p 3d point on plane
|
||||
// n 3d vector of normal of plane pointing away from inside
|
||||
// Outputs:
|
||||
// VC #VC by 3 list of vertex positions of boolean result mesh
|
||||
// FC #FC by 3 list of triangle indices into VC
|
||||
// J #FC list of indices into [F;F.rows()+[1;2]] revealing "birth"
|
||||
// facet
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename Derivedp,
|
||||
typename Derivedn,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool intersect_with_half_space(
|
||||
const Eigen::MatrixBase<DerivedV > & V,
|
||||
const Eigen::MatrixBase<DerivedF > & F,
|
||||
const Eigen::MatrixBase<Derivedp > & p,
|
||||
const Eigen::MatrixBase<Derivedn > & n,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J);
|
||||
// Intersect a PWN mesh with a half-space. Plane equation.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of mesh vertex positions
|
||||
// equ plane equation: P(x,y,z) = a*x+b*y+c*z + d = 0, P(x,y,z) < 0 is
|
||||
// _inside_.
|
||||
// Outputs:
|
||||
// VC #VC by 3 list of vertex positions of boolean result mesh
|
||||
// FC #FC by 3 list of triangle indices into VC
|
||||
// J #FC list of indices into [F;F.rows()+[1;2]] revealing "birth" facet
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename Derivedequ,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool intersect_with_half_space(
|
||||
const Eigen::MatrixBase<DerivedV > & V,
|
||||
const Eigen::MatrixBase<DerivedF > & F,
|
||||
const Eigen::MatrixBase<Derivedequ > & equ,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J);
|
||||
// Intersect a PWN mesh with a half-space. CGAL Plane.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of mesh vertex positions
|
||||
// P plane
|
||||
// Outputs:
|
||||
// VC #VC by 3 list of vertex positions of boolean result mesh
|
||||
// FC #FC by 3 list of triangle indices into VC
|
||||
// J #FC list of indices into [F;F.rows()+[1;2]] revealing "birth" facet
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool intersect_with_half_space(
|
||||
const Eigen::MatrixBase<DerivedV > & V,
|
||||
const Eigen::MatrixBase<DerivedF > & F,
|
||||
const CGAL::Plane_3<CGAL::Epeck> & P,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "intersect_with_half_space.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
24
src/libigl/igl/copyleft/cgal/lexicographic_triangulation.cpp
Normal file
24
src/libigl/igl/copyleft/cgal/lexicographic_triangulation.cpp
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
|
||||
// Qingan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "lexicographic_triangulation.h"
|
||||
#include "../../lexicographic_triangulation.h"
|
||||
#include "orient2D.h"
|
||||
|
||||
template<
|
||||
typename DerivedP,
|
||||
typename DerivedF
|
||||
>
|
||||
IGL_INLINE void igl::copyleft::cgal::lexicographic_triangulation(
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
Eigen::PlainObjectBase<DerivedF>& F)
|
||||
{
|
||||
typedef typename DerivedP::Scalar Scalar;
|
||||
igl::lexicographic_triangulation(P, orient2D<Scalar>, F);
|
||||
}
|
||||
47
src/libigl/igl/copyleft/cgal/lexicographic_triangulation.h
Normal file
47
src/libigl/igl/copyleft/cgal/lexicographic_triangulation.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
|
||||
// Qingan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef IGL_COPYLEFT_CGAL_LEXICOGRAPHIC_TRIANGULATION_H
|
||||
#define IGL_COPYLEFT_CGAL_LEXICOGRAPHIC_TRIANGULATION_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
|
||||
// Given a set of points in 2D, return a lexicographic triangulation of these
|
||||
// points.
|
||||
//
|
||||
// Inputs:
|
||||
// P #P by 2 list of vertex positions
|
||||
//
|
||||
// Outputs:
|
||||
// F #F by 3 of faces in lexicographic triangulation.
|
||||
template<
|
||||
typename DerivedP,
|
||||
typename DerivedF
|
||||
>
|
||||
IGL_INLINE void lexicographic_triangulation(
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
Eigen::PlainObjectBase<DerivedF>& F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "lexicographic_triangulation.cpp"
|
||||
#endif
|
||||
#endif
|
||||
15
src/libigl/igl/copyleft/cgal/list_to_matrix.cpp
Normal file
15
src/libigl/igl/copyleft/cgal/list_to_matrix.cpp
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "../../list_to_matrix.h"
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
#undef IGL_STATIC_LIBRARY
|
||||
#include "../../list_to_matrix.cpp"
|
||||
template bool igl::list_to_matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >(std::vector<std::vector<CGAL::Lazy_exact_nt<CGAL::Gmpq>, std::allocator<CGAL::Lazy_exact_nt<CGAL::Gmpq> > >, std::allocator<std::vector<CGAL::Lazy_exact_nt<CGAL::Gmpq>, std::allocator<CGAL::Lazy_exact_nt<CGAL::Gmpq> > > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&);
|
||||
#endif
|
||||
466
src/libigl/igl/copyleft/cgal/mesh_boolean.cpp
Normal file
466
src/libigl/igl/copyleft/cgal/mesh_boolean.cpp
Normal file
|
|
@ -0,0 +1,466 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
// Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
#include "mesh_boolean.h"
|
||||
#include "assign.h"
|
||||
#include "extract_cells.h"
|
||||
#include "mesh_boolean_type_to_funcs.h"
|
||||
#include "propagate_winding_numbers.h"
|
||||
#include "relabel_small_immersed_cells.h"
|
||||
#include "remesh_self_intersections.h"
|
||||
#include "string_to_mesh_boolean_type.h"
|
||||
#include "../../combine.h"
|
||||
#include "../../cumsum.h"
|
||||
#include "../../extract_manifold_patches.h"
|
||||
#include "../../get_seconds.h"
|
||||
#include "../../remove_unreferenced.h"
|
||||
#include "../../resolve_duplicated_faces.h"
|
||||
#include "../../slice.h"
|
||||
#include "../../unique_edge_map.h"
|
||||
#include "../../unique_simplices.h"
|
||||
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <algorithm>
|
||||
|
||||
//#define MESH_BOOLEAN_TIMING
|
||||
//#define DOUBLE_CHECK_EXACT_OUTPUT
|
||||
//#define SMALL_CELL_REMOVAL
|
||||
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
|
||||
const Eigen::MatrixBase<DerivedVA > & VA,
|
||||
const Eigen::MatrixBase<DerivedFA > & FA,
|
||||
const Eigen::MatrixBase<DerivedVB > & VB,
|
||||
const Eigen::MatrixBase<DerivedFB > & FB,
|
||||
const MeshBooleanType & type,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J)
|
||||
{
|
||||
std::function<int(const int, const int)> keep;
|
||||
std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) > wind_num_op;
|
||||
mesh_boolean_type_to_funcs(type,wind_num_op,keep);
|
||||
return mesh_boolean(VA,FA,VB,FB,wind_num_op,keep,VC,FC,J);
|
||||
}
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
|
||||
const Eigen::MatrixBase<DerivedVA > & VA,
|
||||
const Eigen::MatrixBase<DerivedFA > & FA,
|
||||
const Eigen::MatrixBase<DerivedVB > & VB,
|
||||
const Eigen::MatrixBase<DerivedFB > & FB,
|
||||
const std::string & type_str,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J)
|
||||
{
|
||||
return mesh_boolean(
|
||||
VA,FA,VB,FB,string_to_mesh_boolean_type(type_str),VC,FC,J);
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
|
||||
const Eigen::MatrixBase<DerivedVA> & VA,
|
||||
const Eigen::MatrixBase<DerivedFA> & FA,
|
||||
const Eigen::MatrixBase<DerivedVB> & VB,
|
||||
const Eigen::MatrixBase<DerivedFB> & FB,
|
||||
const std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >& wind_num_op,
|
||||
const std::function<int(const int, const int)> & keep,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J)
|
||||
{
|
||||
// Generate combined mesh (VA,FA,VB,FB) -> (V,F)
|
||||
Eigen::Matrix<size_t,2,1> sizes(FA.rows(),FB.rows());
|
||||
// TODO: This is a precision template **bug** that results in failure to
|
||||
// compile. If DerivedVA::Scalar is double and DerivedVB::Scalar is
|
||||
// CGAL::Epeck::FT then the following assignment will not compile. This
|
||||
// implies that VA must have the trumping precision (and a valid assignment
|
||||
// operator from VB's type).
|
||||
Eigen::Matrix<typename DerivedVA::Scalar,Eigen::Dynamic,3> VV(VA.rows() + VB.rows(), 3);
|
||||
DerivedFC FF(FA.rows() + FB.rows(), 3);
|
||||
// Can't use comma initializer
|
||||
for(int a = 0;a<VA.rows();a++)
|
||||
{
|
||||
for(int d = 0;d<3;d++) VV(a,d) = VA(a,d);
|
||||
}
|
||||
for(int b = 0;b<VB.rows();b++)
|
||||
{
|
||||
for(int d = 0;d<3;d++) VV(VA.rows()+b,d) = VB(b,d);
|
||||
}
|
||||
FF.block(0, 0, FA.rows(), 3) = FA;
|
||||
// Eigen struggles to assign nothing to nothing and will assert if FB is empty
|
||||
if(FB.rows() > 0)
|
||||
{
|
||||
FF.block(FA.rows(), 0, FB.rows(), 3) = FB.array() + VA.rows();
|
||||
}
|
||||
return mesh_boolean(VV,FF,sizes,wind_num_op,keep,VC,FC,J);
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
|
||||
const std::vector<DerivedV > & Vlist,
|
||||
const std::vector<DerivedF > & Flist,
|
||||
const std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >& wind_num_op,
|
||||
const std::function<int(const int, const int)> & keep,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J)
|
||||
{
|
||||
DerivedV VV;
|
||||
DerivedF FF;
|
||||
Eigen::Matrix<size_t,Eigen::Dynamic,1> Vsizes,Fsizes;
|
||||
igl::combine(Vlist,Flist,VV,FF,Vsizes,Fsizes);
|
||||
return mesh_boolean(VV,FF,Fsizes,wind_num_op,keep,VC,FC,J);
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
|
||||
const std::vector<DerivedV > & Vlist,
|
||||
const std::vector<DerivedF > & Flist,
|
||||
const MeshBooleanType & type,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J)
|
||||
{
|
||||
DerivedV VV;
|
||||
DerivedF FF;
|
||||
Eigen::Matrix<size_t,Eigen::Dynamic,1> Vsizes,Fsizes;
|
||||
igl::combine(Vlist,Flist,VV,FF,Vsizes,Fsizes);
|
||||
std::function<int(const int, const int)> keep;
|
||||
std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) > wind_num_op;
|
||||
mesh_boolean_type_to_funcs(type,wind_num_op,keep);
|
||||
return mesh_boolean(VV,FF,Fsizes,wind_num_op,keep,VC,FC,J);
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename Derivedsizes,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
|
||||
const Eigen::MatrixBase<DerivedVV > & VV,
|
||||
const Eigen::MatrixBase<DerivedFF > & FF,
|
||||
const Eigen::MatrixBase<Derivedsizes> & sizes,
|
||||
const std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >& wind_num_op,
|
||||
const std::function<int(const int, const int)> & keep,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J)
|
||||
{
|
||||
#ifdef MESH_BOOLEAN_TIMING
|
||||
const auto & tictoc = []() -> double
|
||||
{
|
||||
static double t_start = igl::get_seconds();
|
||||
double diff = igl::get_seconds()-t_start;
|
||||
t_start += diff;
|
||||
return diff;
|
||||
};
|
||||
const auto log_time = [&](const std::string& label) -> void {
|
||||
std::cout << "mesh_boolean." << label << ": "
|
||||
<< tictoc() << std::endl;
|
||||
};
|
||||
tictoc();
|
||||
#endif
|
||||
typedef typename DerivedVC::Scalar Scalar;
|
||||
typedef CGAL::Epeck Kernel;
|
||||
typedef Kernel::FT ExactScalar;
|
||||
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,3> MatrixX3S;
|
||||
typedef Eigen::Matrix<typename DerivedJ::Scalar,Eigen::Dynamic,1> VectorXJ;
|
||||
typedef Eigen::Matrix<
|
||||
ExactScalar,
|
||||
Eigen::Dynamic,
|
||||
Eigen::Dynamic,
|
||||
DerivedVC::IsRowMajor> MatrixXES;
|
||||
MatrixXES V;
|
||||
DerivedFC F;
|
||||
VectorXJ CJ;
|
||||
{
|
||||
Eigen::VectorXi I;
|
||||
igl::copyleft::cgal::RemeshSelfIntersectionsParam params;
|
||||
params.stitch_all = true;
|
||||
MatrixXES Vr;
|
||||
DerivedFC Fr;
|
||||
Eigen::MatrixXi IF;
|
||||
igl::copyleft::cgal::remesh_self_intersections(
|
||||
VV, FF, params, Vr, Fr, IF, CJ, I);
|
||||
assert(I.size() == Vr.rows());
|
||||
// Merge coinciding vertices into non-manifold vertices.
|
||||
std::for_each(Fr.data(), Fr.data()+Fr.size(),
|
||||
[&I](typename DerivedFC::Scalar& a) { a=I[a]; });
|
||||
// Remove unreferenced vertices.
|
||||
Eigen::VectorXi UIM;
|
||||
igl::remove_unreferenced(Vr, Fr, V, F, UIM);
|
||||
}
|
||||
#ifdef MESH_BOOLEAN_TIMING
|
||||
log_time("resolve_self_intersection");
|
||||
#endif
|
||||
|
||||
// Compute edges of (F) --> (E,uE,EMAP,uE2E)
|
||||
Eigen::MatrixXi E, uE;
|
||||
Eigen::VectorXi EMAP;
|
||||
std::vector<std::vector<size_t> > uE2E;
|
||||
igl::unique_edge_map(F, E, uE, EMAP, uE2E);
|
||||
|
||||
// Compute patches (F,EMAP,uE2E) --> (P)
|
||||
Eigen::VectorXi P;
|
||||
const size_t num_patches = igl::extract_manifold_patches(F, EMAP, uE2E, P);
|
||||
#ifdef MESH_BOOLEAN_TIMING
|
||||
log_time("patch_extraction");
|
||||
#endif
|
||||
|
||||
// Compute cells (V,F,P,E,uE,EMAP) -> (per_patch_cells)
|
||||
Eigen::MatrixXi per_patch_cells;
|
||||
const size_t num_cells =
|
||||
igl::copyleft::cgal::extract_cells(
|
||||
V, F, P, E, uE, uE2E, EMAP, per_patch_cells);
|
||||
#ifdef MESH_BOOLEAN_TIMING
|
||||
log_time("cell_extraction");
|
||||
#endif
|
||||
|
||||
// Compute winding numbers on each side of each facet.
|
||||
const size_t num_faces = F.rows();
|
||||
// W(f,:) --> [w1out,w1in,w2out,w2in, ... wnout,wnint] winding numbers above
|
||||
// and below each face w.r.t. each input mesh, so that W(f,2*i) is the
|
||||
// winding number above face f w.r.t. input i, and W(f,2*i+1) is the winding
|
||||
// number below face f w.r.t. input i.
|
||||
Eigen::MatrixXi W;
|
||||
// labels(f) = i means that face f comes from mesh i
|
||||
Eigen::VectorXi labels(num_faces);
|
||||
// cumulative sizes
|
||||
Derivedsizes cumsizes;
|
||||
igl::cumsum(sizes,1,cumsizes);
|
||||
const size_t num_inputs = sizes.size();
|
||||
std::transform(
|
||||
CJ.data(),
|
||||
CJ.data()+CJ.size(),
|
||||
labels.data(),
|
||||
// Determine which input mesh birth face i comes from
|
||||
[&num_inputs,&cumsizes](int i)->int
|
||||
{
|
||||
for(int k = 0;k<num_inputs;k++)
|
||||
{
|
||||
if(i<cumsizes(k)) return k;
|
||||
}
|
||||
assert(false && "Birth parent index out of range");
|
||||
return -1;
|
||||
});
|
||||
bool valid = true;
|
||||
if (num_faces > 0)
|
||||
{
|
||||
valid = valid &
|
||||
igl::copyleft::cgal::propagate_winding_numbers(
|
||||
V, F, uE, uE2E, num_patches, P, num_cells, per_patch_cells, labels, W);
|
||||
} else
|
||||
{
|
||||
W.resize(0, 2*num_inputs);
|
||||
}
|
||||
assert((size_t)W.rows() == num_faces);
|
||||
// If W doesn't have enough columns, pad with zeros
|
||||
if (W.cols() <= 2*num_inputs)
|
||||
{
|
||||
const int old_ncols = W.cols();
|
||||
W.conservativeResize(num_faces,2*num_inputs);
|
||||
W.rightCols(2*num_inputs-old_ncols).setConstant(0);
|
||||
}
|
||||
assert((size_t)W.cols() == 2*num_inputs);
|
||||
#ifdef MESH_BOOLEAN_TIMING
|
||||
log_time("propagate_input_winding_number");
|
||||
#endif
|
||||
|
||||
// Compute resulting winding number.
|
||||
Eigen::MatrixXi Wr(num_faces, 2);
|
||||
for (size_t i=0; i<num_faces; i++)
|
||||
{
|
||||
// Winding number vectors above and below
|
||||
Eigen::RowVectorXi w_out(1,num_inputs), w_in(1,num_inputs);
|
||||
for(size_t k =0;k<num_inputs;k++)
|
||||
{
|
||||
w_out(k) = W(i,2*k+0);
|
||||
w_in(k) = W(i,2*k+1);
|
||||
}
|
||||
Wr(i,0) = wind_num_op(w_out);
|
||||
Wr(i,1) = wind_num_op(w_in);
|
||||
}
|
||||
#ifdef MESH_BOOLEAN_TIMING
|
||||
log_time("compute_output_winding_number");
|
||||
#endif
|
||||
|
||||
#ifdef SMALL_CELL_REMOVAL
|
||||
igl::copyleft::cgal::relabel_small_immersed_cells(
|
||||
V, F, num_patches, P, num_cells, per_patch_cells, 1e-3, Wr);
|
||||
#endif
|
||||
|
||||
// Extract boundary separating inside from outside.
|
||||
auto index_to_signed_index = [&](size_t i, bool ori) -> int
|
||||
{
|
||||
return (i+1)*(ori?1:-1);
|
||||
};
|
||||
//auto signed_index_to_index = [&](int i) -> size_t {
|
||||
// return abs(i) - 1;
|
||||
//};
|
||||
std::vector<int> selected;
|
||||
for(size_t i=0; i<num_faces; i++)
|
||||
{
|
||||
auto should_keep = keep(Wr(i,0), Wr(i,1));
|
||||
if (should_keep > 0)
|
||||
{
|
||||
selected.push_back(index_to_signed_index(i, true));
|
||||
} else if (should_keep < 0)
|
||||
{
|
||||
selected.push_back(index_to_signed_index(i, false));
|
||||
}
|
||||
}
|
||||
|
||||
const size_t num_selected = selected.size();
|
||||
DerivedFC kept_faces(num_selected, 3);
|
||||
DerivedJ kept_face_indices(num_selected, 1);
|
||||
for (size_t i=0; i<num_selected; i++)
|
||||
{
|
||||
size_t idx = abs(selected[i]) - 1;
|
||||
if (selected[i] > 0)
|
||||
{
|
||||
kept_faces.row(i) = F.row(idx);
|
||||
} else
|
||||
{
|
||||
kept_faces.row(i) = F.row(idx).reverse();
|
||||
}
|
||||
kept_face_indices(i, 0) = CJ[idx];
|
||||
}
|
||||
#ifdef MESH_BOOLEAN_TIMING
|
||||
log_time("extract_output");
|
||||
#endif
|
||||
|
||||
// Finally, remove duplicated faces and unreferenced vertices.
|
||||
{
|
||||
DerivedFC G;
|
||||
DerivedJ JJ;
|
||||
igl::resolve_duplicated_faces(kept_faces, G, JJ);
|
||||
igl::slice(kept_face_indices, JJ, 1, J);
|
||||
|
||||
#ifdef DOUBLE_CHECK_EXACT_OUTPUT
|
||||
{
|
||||
// Sanity check on exact output.
|
||||
igl::copyleft::cgal::RemeshSelfIntersectionsParam params;
|
||||
params.detect_only = true;
|
||||
params.first_only = true;
|
||||
MatrixXES dummy_VV;
|
||||
DerivedFC dummy_FF, dummy_IF;
|
||||
Eigen::VectorXi dummy_J, dummy_IM;
|
||||
igl::copyleft::cgal::SelfIntersectMesh<
|
||||
Kernel,
|
||||
MatrixXES, DerivedFC,
|
||||
MatrixXES, DerivedFC,
|
||||
DerivedFC,
|
||||
Eigen::VectorXi,
|
||||
Eigen::VectorXi
|
||||
> checker(V, G, params,
|
||||
dummy_VV, dummy_FF, dummy_IF, dummy_J, dummy_IM);
|
||||
if (checker.count != 0)
|
||||
{
|
||||
throw "Self-intersection not fully resolved.";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
MatrixX3S Vs;
|
||||
assign(V,Vs);
|
||||
Eigen::VectorXi newIM;
|
||||
igl::remove_unreferenced(Vs,G,VC,FC,newIM);
|
||||
}
|
||||
#ifdef MESH_BOOLEAN_TIMING
|
||||
log_time("clean_up");
|
||||
#endif
|
||||
return valid;
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC>
|
||||
IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
|
||||
const Eigen::MatrixBase<DerivedVA > & VA,
|
||||
const Eigen::MatrixBase<DerivedFA > & FA,
|
||||
const Eigen::MatrixBase<DerivedVB > & VB,
|
||||
const Eigen::MatrixBase<DerivedFB > & FB,
|
||||
const MeshBooleanType & type,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedFC::Index, Eigen::Dynamic,1> J;
|
||||
return igl::copyleft::cgal::mesh_boolean(VA,FA,VB,FB,type,VC,FC,J);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 4, 0, -1, 4>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 4, 0, -1, 4>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 4, 0, -1, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 4, 0, -1, 4> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(std::vector<Eigen::Matrix<double, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<double, -1, -1, 0, -1, -1> > > const&, std::vector<Eigen::Matrix<int, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<int, -1, -1, 0, -1, -1> > > const&, std::function<int (Eigen::Matrix<int, 1, -1, 1, 1, -1>)> const&, std::function<int (int, int)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(std::vector<Eigen::Matrix<double, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<double, -1, -1, 0, -1, -1> > > const&, std::vector<Eigen::Matrix<int, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<int, -1, -1, 0, -1, -1> > > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#ifdef WIN32
|
||||
template bool igl::copyleft::cgal::mesh_boolean<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::MatrixBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> const &, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::MatrixBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> const &, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, enum igl::MeshBooleanType const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
|
||||
#endif
|
||||
#endif
|
||||
229
src/libigl/igl/copyleft/cgal/mesh_boolean.h
Normal file
229
src/libigl/igl/copyleft/cgal/mesh_boolean.h
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
// Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
#ifndef IGL_COPYLEFT_CGAL_MESH_BOOLEAN_H
|
||||
#define IGL_COPYLEFT_CGAL_MESH_BOOLEAN_H
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
#include "../../MeshBooleanType.h"
|
||||
#include <Eigen/Core>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// MESH_BOOLEAN Compute boolean csg operations on "solid", consistently
|
||||
// oriented meshes.
|
||||
//
|
||||
// Inputs:
|
||||
// VA #VA by 3 list of vertex positions of first mesh
|
||||
// FA #FA by 3 list of triangle indices into VA
|
||||
// VB #VB by 3 list of vertex positions of second mesh
|
||||
// FB #FB by 3 list of triangle indices into VB
|
||||
// type type of boolean operation
|
||||
// Outputs:
|
||||
// VC #VC by 3 list of vertex positions of boolean result mesh
|
||||
// FC #FC by 3 list of triangle indices into VC
|
||||
// J #FC list of indices into [FA;FA.rows()+FB] revealing "birth" facet
|
||||
// Returns true if inputs induce a piecewise constant winding number
|
||||
// field and type is valid
|
||||
//
|
||||
// See also: mesh_boolean_cork, intersect_other,
|
||||
// remesh_self_intersections
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool mesh_boolean(
|
||||
const Eigen::MatrixBase<DerivedVA > & VA,
|
||||
const Eigen::MatrixBase<DerivedFA > & FA,
|
||||
const Eigen::MatrixBase<DerivedVB > & VB,
|
||||
const Eigen::MatrixBase<DerivedFB > & FB,
|
||||
const MeshBooleanType & type,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J);
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool mesh_boolean(
|
||||
const Eigen::MatrixBase<DerivedVA > & VA,
|
||||
const Eigen::MatrixBase<DerivedFA > & FA,
|
||||
const Eigen::MatrixBase<DerivedVB > & VB,
|
||||
const Eigen::MatrixBase<DerivedFB > & FB,
|
||||
const std::string & type_str,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J);
|
||||
//
|
||||
// Inputs:
|
||||
// VA #VA by 3 list of vertex positions of first mesh
|
||||
// FA #FA by 3 list of triangle indices into VA
|
||||
// VB #VB by 3 list of vertex positions of second mesh
|
||||
// FB #FB by 3 list of triangle indices into VB
|
||||
// wind_num_op function handle for filtering winding numbers from
|
||||
// tuples of integer values to [0,1] outside/inside values
|
||||
// keep function handle for determining if a patch should be "kept"
|
||||
// in the output based on the winding number on either side
|
||||
// Outputs:
|
||||
// VC #VC by 3 list of vertex positions of boolean result mesh
|
||||
// FC #FC by 3 list of triangle indices into VC
|
||||
// J #FC list of indices into [FA;FB] revealing "birth" facet
|
||||
// Returns true iff inputs induce a piecewise constant winding number
|
||||
// field
|
||||
//
|
||||
// See also: mesh_boolean_cork, intersect_other,
|
||||
// remesh_self_intersections
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool mesh_boolean(
|
||||
const Eigen::MatrixBase<DerivedVA> & VA,
|
||||
const Eigen::MatrixBase<DerivedFA> & FA,
|
||||
const Eigen::MatrixBase<DerivedVB> & VB,
|
||||
const Eigen::MatrixBase<DerivedFB> & FB,
|
||||
const std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >& wind_num_op,
|
||||
const std::function<int(const int, const int)> & keep,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J);
|
||||
// MESH_BOOLEAN Variadic boolean operations
|
||||
//
|
||||
// Inputs:
|
||||
// Vlist k-long list of lists of mesh vertex positions
|
||||
// Flist k-long list of lists of mesh face indices, so that Flist[i] indexes
|
||||
// vertices in Vlist[i]
|
||||
// wind_num_op function handle for filtering winding numbers from
|
||||
// n-tuples of integer values to [0,1] outside/inside values
|
||||
// keep function handle for determining if a patch should be "kept"
|
||||
// in the output based on the winding number on either side
|
||||
// Outputs:
|
||||
// VC #VC by 3 list of vertex positions of boolean result mesh
|
||||
// FC #FC by 3 list of triangle indices into VC
|
||||
// J #FC list of indices into [Flist[0];Flist[1];...;Flist[k]]
|
||||
// revealing "birth" facet
|
||||
// Returns true iff inputs induce a piecewise constant winding number
|
||||
// field
|
||||
//
|
||||
// See also: mesh_boolean_cork, intersect_other,
|
||||
// remesh_self_intersections
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool mesh_boolean(
|
||||
const std::vector<DerivedV > & Vlist,
|
||||
const std::vector<DerivedF > & Flist,
|
||||
const std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >& wind_num_op,
|
||||
const std::function<int(const int, const int)> & keep,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J);
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool mesh_boolean(
|
||||
const std::vector<DerivedV > & Vlist,
|
||||
const std::vector<DerivedF > & Flist,
|
||||
const MeshBooleanType & type,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J);
|
||||
// Given a merged mesh (V,F) and list of sizes of inputs
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of merged mesh vertex positions
|
||||
// F #F by 3 list of merged mesh face indices so that first sizes(0)
|
||||
// faces come from the first input, and the next sizes(1) faces come
|
||||
// from the second input, and so on.
|
||||
// sizes #inputs list of sizes so that sizes(i) is the #faces in the
|
||||
// ith input
|
||||
// wind_num_op function handle for filtering winding numbers from
|
||||
// tuples of integer values to [0,1] outside/inside values
|
||||
// keep function handle for determining if a patch should be "kept"
|
||||
// in the output based on the winding number on either side
|
||||
// Outputs:
|
||||
// VC #VC by 3 list of vertex positions of boolean result mesh
|
||||
// FC #FC by 3 list of triangle indices into VC
|
||||
// J #FC list of birth parent indices
|
||||
//
|
||||
template <
|
||||
typename DerivedVV,
|
||||
typename DerivedFF,
|
||||
typename Derivedsizes,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE bool mesh_boolean(
|
||||
const Eigen::MatrixBase<DerivedVV > & VV,
|
||||
const Eigen::MatrixBase<DerivedFF > & FF,
|
||||
const Eigen::MatrixBase<Derivedsizes> & sizes,
|
||||
const std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >& wind_num_op,
|
||||
const std::function<int(const int, const int)> & keep,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC,
|
||||
Eigen::PlainObjectBase<DerivedJ > & J);
|
||||
// Inputs:
|
||||
// VA #VA by 3 list of vertex positions of first mesh
|
||||
// FA #FA by 3 list of triangle indices into VA
|
||||
// VB #VB by 3 list of vertex positions of second mesh
|
||||
// FB #FB by 3 list of triangle indices into VB
|
||||
// type type of boolean operation
|
||||
// Outputs:
|
||||
// VC #VC by 3 list of vertex positions of boolean result mesh
|
||||
// FC #FC by 3 list of triangle indices into VC
|
||||
// Returns true ff inputs induce a piecewise constant winding number
|
||||
// field and type is valid
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedVC,
|
||||
typename DerivedFC>
|
||||
IGL_INLINE bool mesh_boolean(
|
||||
const Eigen::MatrixBase<DerivedVA > & VA,
|
||||
const Eigen::MatrixBase<DerivedFA > & FA,
|
||||
const Eigen::MatrixBase<DerivedVB > & VB,
|
||||
const Eigen::MatrixBase<DerivedFB > & FB,
|
||||
const MeshBooleanType & type,
|
||||
Eigen::PlainObjectBase<DerivedVC > & VC,
|
||||
Eigen::PlainObjectBase<DerivedFC > & FC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "mesh_boolean.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
39
src/libigl/igl/copyleft/cgal/mesh_boolean_type_to_funcs.cpp
Normal file
39
src/libigl/igl/copyleft/cgal/mesh_boolean_type_to_funcs.cpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#include "mesh_boolean_type_to_funcs.h"
|
||||
#include "BinaryWindingNumberOperations.h"
|
||||
|
||||
IGL_INLINE void igl::copyleft::cgal::mesh_boolean_type_to_funcs(
|
||||
const MeshBooleanType & type,
|
||||
std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >& wind_num_op,
|
||||
std::function<int(const int, const int)> & keep)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MESH_BOOLEAN_TYPE_UNION:
|
||||
wind_num_op = BinaryUnion();
|
||||
keep = KeepInside();
|
||||
return;
|
||||
case MESH_BOOLEAN_TYPE_INTERSECT:
|
||||
wind_num_op = BinaryIntersect();
|
||||
keep = KeepInside();
|
||||
return;
|
||||
case MESH_BOOLEAN_TYPE_MINUS:
|
||||
wind_num_op = BinaryMinus();
|
||||
keep = KeepInside();
|
||||
return;
|
||||
case MESH_BOOLEAN_TYPE_XOR:
|
||||
wind_num_op = BinaryXor();
|
||||
keep = KeepInside();
|
||||
return;
|
||||
case MESH_BOOLEAN_TYPE_RESOLVE:
|
||||
wind_num_op = BinaryResolve();
|
||||
keep = KeepAll();
|
||||
return;
|
||||
default:
|
||||
assert(false && "Unsupported boolean type.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
#endif
|
||||
37
src/libigl/igl/copyleft/cgal/mesh_boolean_type_to_funcs.h
Normal file
37
src/libigl/igl/copyleft/cgal/mesh_boolean_type_to_funcs.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef IGL_COPYLEFT_CGAL_MESH_BOOLEAN_TYPE_TO_FUNCS_H
|
||||
#define IGL_COPYLEFT_CGAL_MESH_BOOLEAN_TYPE_TO_FUNCS_H
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
#include "../../MeshBooleanType.h"
|
||||
#include <Eigen/Core>
|
||||
#include <functional>
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Convert a MeshBooleanType enum to a pair of winding number conversion
|
||||
// function and "keep" function used by mesh_boolean
|
||||
//
|
||||
// Inputs:
|
||||
// type MeshBooleanType enum value
|
||||
// Outputs:
|
||||
// wind_num_op function handle for filtering winding numbers from
|
||||
// tuples of integer values to [0,1] outside/inside values
|
||||
// keep function handle for determining if a patch should be "kept"
|
||||
// in the output based on the winding number on either side
|
||||
//
|
||||
// See also: string_to_mesh_boolean_type
|
||||
IGL_INLINE void mesh_boolean_type_to_funcs(
|
||||
const MeshBooleanType & type,
|
||||
std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >&
|
||||
wind_num_op,
|
||||
std::function<int(const int, const int)> & keep);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "mesh_boolean_type_to_funcs.cpp"
|
||||
#endif
|
||||
#endif
|
||||
76
src/libigl/igl/copyleft/cgal/mesh_to_cgal_triangle_list.cpp
Normal file
76
src/libigl/igl/copyleft/cgal/mesh_to_cgal_triangle_list.cpp
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "mesh_to_cgal_triangle_list.h"
|
||||
#include "assign.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename Kernel>
|
||||
IGL_INLINE void igl::copyleft::cgal::mesh_to_cgal_triangle_list(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
std::vector<CGAL::Triangle_3<Kernel> > & T)
|
||||
{
|
||||
typedef CGAL::Point_3<Kernel> Point_3;
|
||||
typedef CGAL::Triangle_3<Kernel> Triangle_3;
|
||||
// Must be 3D
|
||||
assert(V.cols() == 3);
|
||||
// **Copy** to convert to output type (this is especially/only needed if the
|
||||
// input type DerivedV::Scalar is CGAL::Epeck
|
||||
Eigen::Matrix<
|
||||
typename Kernel::FT,
|
||||
DerivedV::RowsAtCompileTime,
|
||||
DerivedV::ColsAtCompileTime>
|
||||
KV(V.rows(),V.cols());
|
||||
assign(V,KV);
|
||||
// Must be triangles
|
||||
assert(F.cols() == 3);
|
||||
T.reserve(F.rows());
|
||||
// Loop over faces
|
||||
for(int f = 0;f<(int)F.rows();f++)
|
||||
{
|
||||
T.push_back(
|
||||
Triangle_3(
|
||||
Point_3( KV(F(f,0),0), KV(F(f,0),1), KV(F(f,0),2)),
|
||||
Point_3( KV(F(f,1),0), KV(F(f,1),1), KV(F(f,1),2)),
|
||||
Point_3( KV(F(f,2),0), KV(F(f,2),1), KV(F(f,2),2))));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
|
||||
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
|
||||
#endif
|
||||
44
src/libigl/igl/copyleft/cgal/mesh_to_cgal_triangle_list.h
Normal file
44
src/libigl/igl/copyleft/cgal/mesh_to_cgal_triangle_list.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_MESH_TO_CGAL_TRIANGLE_LIST_H
|
||||
#define IGL_COPYLEFT_CGAL_MESH_TO_CGAL_TRIANGLE_LIST_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include "CGAL_includes.hpp"
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Convert a mesh (V,F) to a list of CGAL triangles
|
||||
//
|
||||
// Templates:
|
||||
// Kernal CGAL computation and construction kernel (e.g.
|
||||
// CGAL::Exact_predicates_exact_constructions_kernel)
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices
|
||||
// Outputs:
|
||||
// T #F list of CGAL triangles
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename Kernel>
|
||||
IGL_INLINE void mesh_to_cgal_triangle_list(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
std::vector<CGAL::Triangle_3<Kernel> > & T);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "mesh_to_cgal_triangle_list.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
54
src/libigl/igl/copyleft/cgal/mesh_to_polyhedron.cpp
Normal file
54
src/libigl/igl/copyleft/cgal/mesh_to_polyhedron.cpp
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "mesh_to_polyhedron.h"
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
#include <CGAL/Polyhedron_incremental_builder_3.h>
|
||||
|
||||
|
||||
template <typename Polyhedron>
|
||||
IGL_INLINE bool igl::copyleft::cgal::mesh_to_polyhedron(
|
||||
const Eigen::MatrixXd & V,
|
||||
const Eigen::MatrixXi & F,
|
||||
Polyhedron & poly)
|
||||
{
|
||||
typedef typename Polyhedron::HalfedgeDS HalfedgeDS;
|
||||
// Postcondition: hds is a valid polyhedral surface.
|
||||
CGAL::Polyhedron_incremental_builder_3<HalfedgeDS> B(poly.hds());
|
||||
B.begin_surface(V.rows(),F.rows());
|
||||
typedef typename HalfedgeDS::Vertex Vertex;
|
||||
typedef typename Vertex::Point Point;
|
||||
assert(V.cols() == 3 && "V must be #V by 3");
|
||||
for(int v = 0;v<V.rows();v++)
|
||||
{
|
||||
B.add_vertex(Point(V(v,0),V(v,1),V(v,2)));
|
||||
}
|
||||
assert(F.cols() == 3 && "F must be #F by 3");
|
||||
for(int f=0;f<F.rows();f++)
|
||||
{
|
||||
B.begin_facet();
|
||||
for(int c = 0;c<3;c++)
|
||||
{
|
||||
B.add_vertex_to_facet(F(f,c));
|
||||
}
|
||||
B.end_facet();
|
||||
}
|
||||
if(B.error())
|
||||
{
|
||||
B.rollback();
|
||||
return false;
|
||||
}
|
||||
B.end_surface();
|
||||
return poly.is_valid();
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Polyhedron_items_with_id_3.h>
|
||||
template bool igl::copyleft::cgal::mesh_to_polyhedron<CGAL::Polyhedron_3<CGAL::Simple_cartesian<double>, CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator<int> > >(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, CGAL::Polyhedron_3<CGAL::Simple_cartesian<double>, CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator<int> >&);
|
||||
#endif
|
||||
42
src/libigl/igl/copyleft/cgal/mesh_to_polyhedron.h
Normal file
42
src/libigl/igl/copyleft/cgal/mesh_to_polyhedron.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_MESH_TO_POLYHEDRON_H
|
||||
#define IGL_COPYLEFT_CGAL_MESH_TO_POLYHEDRON_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Convert a mesh (V,F) to a CGAL Polyhedron
|
||||
//
|
||||
// Templates:
|
||||
// Polyhedron CGAL Polyhedron type (e.g. Polyhedron_3)
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices
|
||||
// Outputs:
|
||||
// poly cgal polyhedron
|
||||
// Returns true only if (V,F) can be converted to a valid polyhedron (i.e. if
|
||||
// (V,F) is vertex and edge manifold).
|
||||
template <typename Polyhedron>
|
||||
IGL_INLINE bool mesh_to_polyhedron(
|
||||
const Eigen::MatrixXd & V,
|
||||
const Eigen::MatrixXi & F,
|
||||
Polyhedron & poly);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "mesh_to_polyhedron.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
395
src/libigl/igl/copyleft/cgal/minkowski_sum.cpp
Normal file
395
src/libigl/igl/copyleft/cgal/minkowski_sum.cpp
Normal file
|
|
@ -0,0 +1,395 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "minkowski_sum.h"
|
||||
#include "mesh_boolean.h"
|
||||
|
||||
#include "../../slice.h"
|
||||
#include "../../slice_mask.h"
|
||||
#include "../../LinSpaced.h"
|
||||
#include "../../unique_rows.h"
|
||||
#include "../../get_seconds.h"
|
||||
#include "../../edges.h"
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedW,
|
||||
typename DerivedG,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE void igl::copyleft::cgal::minkowski_sum(
|
||||
const Eigen::MatrixBase<DerivedVA> & VA,
|
||||
const Eigen::MatrixBase<DerivedFA> & FA,
|
||||
const Eigen::MatrixBase<DerivedVB> & VB,
|
||||
const Eigen::MatrixBase<DerivedFB> & FB,
|
||||
const bool resolve_overlaps,
|
||||
Eigen::PlainObjectBase<DerivedW> & W,
|
||||
Eigen::PlainObjectBase<DerivedG> & G,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
assert(FA.cols() == 3 && "FA must contain a closed triangle mesh");
|
||||
assert(FB.cols() <= FA.cols() &&
|
||||
"FB must contain lower diemnsional simplices than FA");
|
||||
const auto tictoc = []()->double
|
||||
{
|
||||
static double t_start;
|
||||
double now = igl::get_seconds();
|
||||
double interval = now-t_start;
|
||||
t_start = now;
|
||||
return interval;
|
||||
};
|
||||
tictoc();
|
||||
Matrix<typename DerivedFB::Scalar,Dynamic,2> EB;
|
||||
edges(FB,EB);
|
||||
Matrix<typename DerivedFA::Scalar,Dynamic,2> EA(0,2);
|
||||
if(FB.cols() == 3)
|
||||
{
|
||||
edges(FA,EA);
|
||||
}
|
||||
// number of copies of A along edges of B
|
||||
const int n_ab = EB.rows();
|
||||
// number of copies of B along edges of A
|
||||
const int n_ba = EA.rows();
|
||||
|
||||
vector<DerivedW> vW(n_ab + n_ba);
|
||||
vector<DerivedG> vG(n_ab + n_ba);
|
||||
vector<DerivedJ> vJ(n_ab + n_ba);
|
||||
vector<int> offsets(n_ab + n_ba + 1);
|
||||
offsets[0] = 0;
|
||||
// sweep A along edges of B
|
||||
for(int e = 0;e<n_ab;e++)
|
||||
{
|
||||
Matrix<typename DerivedJ::Scalar,Dynamic,1> eJ;
|
||||
minkowski_sum(
|
||||
VA,
|
||||
FA,
|
||||
VB.row(EB(e,0)).eval(),
|
||||
VB.row(EB(e,1)).eval(),
|
||||
false,
|
||||
vW[e],
|
||||
vG[e],
|
||||
eJ);
|
||||
assert(vG[e].rows() == eJ.rows());
|
||||
assert(eJ.cols() == 1);
|
||||
vJ[e].resize(vG[e].rows(),2);
|
||||
vJ[e].col(0) = eJ;
|
||||
vJ[e].col(1).setConstant(e);
|
||||
offsets[e+1] = offsets[e] + vW[e].rows();
|
||||
}
|
||||
// sweep B along edges of A
|
||||
for(int e = 0;e<n_ba;e++)
|
||||
{
|
||||
Matrix<typename DerivedJ::Scalar,Dynamic,1> eJ;
|
||||
const int ee = n_ab+e;
|
||||
minkowski_sum(
|
||||
VB,
|
||||
FB,
|
||||
VA.row(EA(e,0)).eval(),
|
||||
VA.row(EA(e,1)).eval(),
|
||||
false,
|
||||
vW[ee],
|
||||
vG[ee],
|
||||
eJ);
|
||||
vJ[ee].resize(vG[ee].rows(),2);
|
||||
vJ[ee].col(0) = eJ.array() + (FA.rows()+1);
|
||||
vJ[ee].col(1).setConstant(ee);
|
||||
offsets[ee+1] = offsets[ee] + vW[ee].rows();
|
||||
}
|
||||
// Combine meshes
|
||||
int n=0,m=0;
|
||||
for_each(vW.begin(),vW.end(),[&n](const DerivedW & w){n+=w.rows();});
|
||||
for_each(vG.begin(),vG.end(),[&m](const DerivedG & g){m+=g.rows();});
|
||||
assert(n == offsets.back());
|
||||
|
||||
W.resize(n,3);
|
||||
G.resize(m,3);
|
||||
J.resize(m,2);
|
||||
{
|
||||
int m_off = 0,n_off = 0;
|
||||
for(int i = 0;i<vG.size();i++)
|
||||
{
|
||||
W.block(n_off,0,vW[i].rows(),3) = vW[i];
|
||||
G.block(m_off,0,vG[i].rows(),3) = vG[i].array()+offsets[i];
|
||||
J.block(m_off,0,vJ[i].rows(),2) = vJ[i];
|
||||
n_off += vW[i].rows();
|
||||
m_off += vG[i].rows();
|
||||
}
|
||||
assert(n == n_off);
|
||||
assert(m == m_off);
|
||||
}
|
||||
if(resolve_overlaps)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedJ::Scalar, Eigen::Dynamic,1> SJ;
|
||||
mesh_boolean(
|
||||
DerivedW(W),
|
||||
DerivedG(G),
|
||||
Matrix<typename DerivedW::Scalar,Dynamic,Dynamic>(),
|
||||
Matrix<typename DerivedG::Scalar,Dynamic,Dynamic>(),
|
||||
MESH_BOOLEAN_TYPE_UNION,
|
||||
W,
|
||||
G,
|
||||
SJ);
|
||||
slice(DerivedJ(J),SJ,1,J);
|
||||
}
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename sType, int sCols, int sOptions,
|
||||
typename dType, int dCols, int dOptions,
|
||||
typename DerivedW,
|
||||
typename DerivedG,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE void igl::copyleft::cgal::minkowski_sum(
|
||||
const Eigen::MatrixBase<DerivedVA> & VA,
|
||||
const Eigen::MatrixBase<DerivedFA> & FA,
|
||||
const Eigen::Matrix<sType,1,sCols,sOptions> & s,
|
||||
const Eigen::Matrix<dType,1,dCols,dOptions> & d,
|
||||
const bool resolve_overlaps,
|
||||
Eigen::PlainObjectBase<DerivedW> & W,
|
||||
Eigen::PlainObjectBase<DerivedG> & G,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J)
|
||||
{
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
assert(s.cols() == 3 && "s should be a 3d point");
|
||||
assert(d.cols() == 3 && "d should be a 3d point");
|
||||
// silly base case
|
||||
if(FA.size() == 0)
|
||||
{
|
||||
W.resize(0,3);
|
||||
G.resize(0,3);
|
||||
return;
|
||||
}
|
||||
const int dim = VA.cols();
|
||||
assert(dim == 3 && "dim must be 3D");
|
||||
assert(s.size() == 3 && "s must be 3D point");
|
||||
assert(d.size() == 3 && "d must be 3D point");
|
||||
// segment vector
|
||||
const CGAL::Vector_3<CGAL::Epeck> v(d(0)-s(0),d(1)-s(1),d(2)-s(2));
|
||||
// number of vertices
|
||||
const int n = VA.rows();
|
||||
// duplicate vertices at s and d, we'll remove unreferernced later
|
||||
W.resize(2*n,dim);
|
||||
for(int i = 0;i<n;i++)
|
||||
{
|
||||
for(int j = 0;j<dim;j++)
|
||||
{
|
||||
W (i,j) = VA(i,j) + s(j);
|
||||
W(i+n,j) = VA(i,j) + d(j);
|
||||
}
|
||||
}
|
||||
// number of faces
|
||||
const int m = FA.rows();
|
||||
//// Mask whether positive dot product, or negative: because of exactly zero,
|
||||
//// these are not necessarily complementary
|
||||
// Nevermind, actually P = !N
|
||||
Matrix<bool,Dynamic,1> P(m,1),N(m,1);
|
||||
// loop over faces
|
||||
int mp = 0,mn = 0;
|
||||
for(int f = 0;f<m;f++)
|
||||
{
|
||||
const CGAL::Plane_3<CGAL::Epeck> plane(
|
||||
CGAL::Point_3<CGAL::Epeck>(VA(FA(f,0),0),VA(FA(f,0),1),VA(FA(f,0),2)),
|
||||
CGAL::Point_3<CGAL::Epeck>(VA(FA(f,1),0),VA(FA(f,1),1),VA(FA(f,1),2)),
|
||||
CGAL::Point_3<CGAL::Epeck>(VA(FA(f,2),0),VA(FA(f,2),1),VA(FA(f,2),2)));
|
||||
const auto normal = plane.orthogonal_vector();
|
||||
const auto dt = normal * v;
|
||||
if(dt > 0)
|
||||
{
|
||||
P(f) = true;
|
||||
N(f) = false;
|
||||
mp++;
|
||||
}else
|
||||
//}else if(dt < 0)
|
||||
{
|
||||
P(f) = false;
|
||||
N(f) = true;
|
||||
mn++;
|
||||
//}else
|
||||
//{
|
||||
// P(f) = false;
|
||||
// N(f) = false;
|
||||
}
|
||||
}
|
||||
|
||||
typedef Matrix<typename DerivedG::Scalar,Dynamic,Dynamic> MatrixXI;
|
||||
typedef Matrix<typename DerivedG::Scalar,Dynamic,1> VectorXI;
|
||||
MatrixXI GT(mp+mn,3);
|
||||
GT<< slice_mask(FA,N,1), slice_mask((FA.array()+n).eval(),P,1);
|
||||
// J indexes FA for parts at s and m+FA for parts at d
|
||||
J.derived() = igl::LinSpaced<DerivedJ >(m,0,m-1);
|
||||
DerivedJ JT(mp+mn);
|
||||
JT << slice_mask(J,P,1), slice_mask(J,N,1);
|
||||
JT.block(mp,0,mn,1).array()+=m;
|
||||
|
||||
// Original non-co-planar faces with positively oriented reversed
|
||||
MatrixXI BA(mp+mn,3);
|
||||
BA << slice_mask(FA,P,1).rowwise().reverse(), slice_mask(FA,N,1);
|
||||
// Quads along **all** sides
|
||||
MatrixXI GQ((mp+mn)*3,4);
|
||||
GQ<<
|
||||
BA.col(1), BA.col(0), BA.col(0).array()+n, BA.col(1).array()+n,
|
||||
BA.col(2), BA.col(1), BA.col(1).array()+n, BA.col(2).array()+n,
|
||||
BA.col(0), BA.col(2), BA.col(2).array()+n, BA.col(0).array()+n;
|
||||
|
||||
MatrixXI uGQ;
|
||||
VectorXI S,sI,sJ;
|
||||
// Inputs:
|
||||
// F #F by d list of polygons
|
||||
// Outputs:
|
||||
// S #uF list of signed incidences for each unique face
|
||||
// uF #uF by d list of unique faces
|
||||
// I #uF index vector so that uF = sort(F,2)(I,:)
|
||||
// J #F index vector so that sort(F,2) = uF(J,:)
|
||||
[](
|
||||
const MatrixXI & F,
|
||||
VectorXI & S,
|
||||
MatrixXI & uF,
|
||||
VectorXI & I,
|
||||
VectorXI & J)
|
||||
{
|
||||
const int m = F.rows();
|
||||
const int d = F.cols();
|
||||
MatrixXI sF = F;
|
||||
const auto MN = sF.rowwise().minCoeff().eval();
|
||||
// rotate until smallest index is first
|
||||
for(int p = 0;p<d;p++)
|
||||
{
|
||||
for(int f = 0;f<m;f++)
|
||||
{
|
||||
if(sF(f,0) != MN(f))
|
||||
{
|
||||
for(int r = 0;r<d-1;r++)
|
||||
{
|
||||
std::swap(sF(f,r),sF(f,r+1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// swap orienation so that last index is greater than first
|
||||
for(int f = 0;f<m;f++)
|
||||
{
|
||||
if(sF(f,d-1) < sF(f,1))
|
||||
{
|
||||
sF.block(f,1,1,d-1) = sF.block(f,1,1,d-1).reverse().eval();
|
||||
}
|
||||
}
|
||||
Matrix<bool,Dynamic,1> M = Matrix<bool,Dynamic,1>::Zero(m,1);
|
||||
{
|
||||
VectorXI P = igl::LinSpaced<VectorXI >(d,0,d-1);
|
||||
for(int p = 0;p<d;p++)
|
||||
{
|
||||
for(int f = 0;f<m;f++)
|
||||
{
|
||||
bool all = true;
|
||||
for(int r = 0;r<d;r++)
|
||||
{
|
||||
all = all && (sF(f,P(r)) == F(f,r));
|
||||
}
|
||||
M(f) = M(f) || all;
|
||||
}
|
||||
for(int r = 0;r<d-1;r++)
|
||||
{
|
||||
std::swap(P(r),P(r+1));
|
||||
}
|
||||
}
|
||||
}
|
||||
unique_rows(sF,uF,I,J);
|
||||
S = VectorXI::Zero(uF.rows(),1);
|
||||
assert(m == J.rows());
|
||||
for(int f = 0;f<m;f++)
|
||||
{
|
||||
S(J(f)) += M(f) ? 1 : -1;
|
||||
}
|
||||
}(MatrixXI(GQ),S,uGQ,sI,sJ);
|
||||
assert(S.rows() == uGQ.rows());
|
||||
const int nq = (S.array().abs()==2).count();
|
||||
GQ.resize(nq,4);
|
||||
{
|
||||
int k = 0;
|
||||
for(int q = 0;q<uGQ.rows();q++)
|
||||
{
|
||||
switch(S(q))
|
||||
{
|
||||
case -2:
|
||||
GQ.row(k++) = uGQ.row(q).reverse().eval();
|
||||
break;
|
||||
case 2:
|
||||
GQ.row(k++) = uGQ.row(q);
|
||||
break;
|
||||
default:
|
||||
// do not add
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(nq == k);
|
||||
}
|
||||
|
||||
G.resize(GT.rows()+2*GQ.rows(),3);
|
||||
G<<
|
||||
GT,
|
||||
GQ.col(0), GQ.col(1), GQ.col(2),
|
||||
GQ.col(0), GQ.col(2), GQ.col(3);
|
||||
J.resize(JT.rows()+2*GQ.rows(),1);
|
||||
J<<JT,DerivedJ::Constant(2*GQ.rows(),1,2*m+1);
|
||||
if(resolve_overlaps)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedJ::Scalar, Eigen::Dynamic,1> SJ;
|
||||
mesh_boolean(
|
||||
DerivedW(W),DerivedG(G),
|
||||
Matrix<typename DerivedVA::Scalar,Dynamic,Dynamic>(),MatrixXI(),
|
||||
MESH_BOOLEAN_TYPE_UNION,
|
||||
W,G,SJ);
|
||||
J.derived() = slice(DerivedJ(J),SJ,1);
|
||||
}
|
||||
}
|
||||
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename sType, int sCols, int sOptions,
|
||||
typename dType, int dCols, int dOptions,
|
||||
typename DerivedW,
|
||||
typename DerivedG,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE void igl::copyleft::cgal::minkowski_sum(
|
||||
const Eigen::MatrixBase<DerivedVA> & VA,
|
||||
const Eigen::MatrixBase<DerivedFA> & FA,
|
||||
const Eigen::Matrix<sType,1,sCols,sOptions> & s,
|
||||
const Eigen::Matrix<dType,1,dCols,dOptions> & d,
|
||||
Eigen::PlainObjectBase<DerivedW> & W,
|
||||
Eigen::PlainObjectBase<DerivedG> & G,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J)
|
||||
{
|
||||
return minkowski_sum(VA,FA,s,d,true,W,G,J);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::minkowski_sum<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, CGAL::Lazy_exact_nt<CGAL::Gmpq>, 3, 1, CGAL::Lazy_exact_nt<CGAL::Gmpq>, 3, 1, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 3, 1, 1, 3> const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 3, 1, 1, 3> const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::minkowski_sum<
|
||||
Eigen::Matrix<float, -1, 3, 1, -1, 3>,
|
||||
Eigen::Matrix<int, -1, 3, 1, -1, 3>,
|
||||
double, 3, 1,
|
||||
float, 3, 1,
|
||||
Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>,
|
||||
Eigen::Matrix<int, -1, -1, 0, -1, -1>,
|
||||
Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, Eigen::Matrix<float, 1, 3, 1, 1, 3> const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
110
src/libigl/igl/copyleft/cgal/minkowski_sum.h
Normal file
110
src/libigl/igl/copyleft/cgal/minkowski_sum.h
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_MINKOWSKI_SUM_H
|
||||
#define IGL_COPYLEFT_CGAL_MINKOWSKI_SUM_H
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Compute the Minkowski sum of a closed triangle mesh (V,F) and a
|
||||
// set of simplices in 3D.
|
||||
//
|
||||
// Inputs:
|
||||
// VA #VA by 3 list of mesh vertices in 3D
|
||||
// FA #FA by 3 list of triangle indices into VA
|
||||
// VB #VB by 3 list of mesh vertices in 3D
|
||||
// FB #FB by ss list of simplex indices into VB, ss<=3
|
||||
// resolve_overlaps whether or not to resolve self-union. If false
|
||||
// then result may contain self-intersections if input mesh is
|
||||
// non-convex.
|
||||
// Outputs:
|
||||
// W #W by 3 list of mesh vertices in 3D
|
||||
// G #G by 3 list of triangle indices into W
|
||||
// J #G by 2 list of indices into
|
||||
//
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedW,
|
||||
typename DerivedG,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE void minkowski_sum(
|
||||
const Eigen::MatrixBase<DerivedVA> & VA,
|
||||
const Eigen::MatrixBase<DerivedFA> & FA,
|
||||
const Eigen::MatrixBase<DerivedVB> & VB,
|
||||
const Eigen::MatrixBase<DerivedFB> & FB,
|
||||
const bool resolve_overlaps,
|
||||
Eigen::PlainObjectBase<DerivedW> & W,
|
||||
Eigen::PlainObjectBase<DerivedG> & G,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J);
|
||||
// Compute the Minkowski sum of a closed triangle mesh (V,F) and a
|
||||
// segment [s,d] in 3D.
|
||||
//
|
||||
// Inputs:
|
||||
// VA #VA by 3 list of mesh vertices in 3D
|
||||
// FA #FA by 3 list of triangle indices into VA
|
||||
// s segment source endpoint in 3D
|
||||
// d segment source endpoint in 3D
|
||||
// resolve_overlaps whether or not to resolve self-union. If false
|
||||
// then result may contain self-intersections if input mesh is
|
||||
// non-convex.
|
||||
// Outputs:
|
||||
// W #W by 3 list of mesh vertices in 3D
|
||||
// G #G by 3 list of triangle indices into W
|
||||
// J #G list of indices into [F;#V+F;[s d]] of birth parents
|
||||
//
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename sType, int sCols, int sOptions,
|
||||
typename dType, int dCols, int dOptions,
|
||||
typename DerivedW,
|
||||
typename DerivedG,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE void minkowski_sum(
|
||||
const Eigen::MatrixBase<DerivedVA> & VA,
|
||||
const Eigen::MatrixBase<DerivedFA> & FA,
|
||||
const Eigen::Matrix<sType,1,sCols,sOptions> & s,
|
||||
const Eigen::Matrix<dType,1,dCols,dOptions> & d,
|
||||
const bool resolve_overlaps,
|
||||
Eigen::PlainObjectBase<DerivedW> & W,
|
||||
Eigen::PlainObjectBase<DerivedG> & G,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J);
|
||||
template <
|
||||
typename DerivedVA,
|
||||
typename DerivedFA,
|
||||
typename sType, int sCols, int sOptions,
|
||||
typename dType, int dCols, int dOptions,
|
||||
typename DerivedW,
|
||||
typename DerivedG,
|
||||
typename DerivedJ>
|
||||
IGL_INLINE void minkowski_sum(
|
||||
const Eigen::MatrixBase<DerivedVA> & VA,
|
||||
const Eigen::MatrixBase<DerivedFA> & FA,
|
||||
const Eigen::Matrix<sType,1,sCols,sOptions> & s,
|
||||
const Eigen::Matrix<dType,1,dCols,dOptions> & d,
|
||||
Eigen::PlainObjectBase<DerivedW> & W,
|
||||
Eigen::PlainObjectBase<DerivedG> & G,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "minkowski_sum.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
428
src/libigl/igl/copyleft/cgal/order_facets_around_edge.cpp
Normal file
428
src/libigl/igl/copyleft/cgal/order_facets_around_edge.cpp
Normal file
|
|
@ -0,0 +1,428 @@
|
|||
#include "order_facets_around_edge.h"
|
||||
#include <Eigen/Geometry>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
// adj_faces contains signed index starting from +- 1.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI >
|
||||
void igl::copyleft::cgal::order_facets_around_edge(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
size_t s,
|
||||
size_t d,
|
||||
const std::vector<int>& adj_faces,
|
||||
Eigen::PlainObjectBase<DerivedI>& order, bool debug)
|
||||
{
|
||||
// Although we only need exact predicates in the algorithm,
|
||||
// exact constructions are needed to avoid degeneracies due to
|
||||
// casting to double.
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel K;
|
||||
typedef K::Point_3 Point_3;
|
||||
typedef K::Plane_3 Plane_3;
|
||||
|
||||
auto get_face_index = [&](int adj_f)->size_t
|
||||
{
|
||||
return abs(adj_f) - 1;
|
||||
};
|
||||
|
||||
auto get_opposite_vertex = [&](size_t fid)->size_t
|
||||
{
|
||||
typedef typename DerivedF::Scalar Index;
|
||||
if (F(fid, 0) != (Index)s && F(fid, 0) != (Index)d) return F(fid, 0);
|
||||
if (F(fid, 1) != (Index)s && F(fid, 1) != (Index)d) return F(fid, 1);
|
||||
if (F(fid, 2) != (Index)s && F(fid, 2) != (Index)d) return F(fid, 2);
|
||||
assert(false);
|
||||
return -1;
|
||||
};
|
||||
|
||||
// Handle base cases
|
||||
if (adj_faces.size() == 0)
|
||||
{
|
||||
order.resize(0, 1);
|
||||
return;
|
||||
} else if (adj_faces.size() == 1)
|
||||
{
|
||||
order.resize(1, 1);
|
||||
order(0, 0) = 0;
|
||||
return;
|
||||
} else if (adj_faces.size() == 2)
|
||||
{
|
||||
const size_t o1 = get_opposite_vertex(get_face_index(adj_faces[0]));
|
||||
const size_t o2 = get_opposite_vertex(get_face_index(adj_faces[1]));
|
||||
const Point_3 ps(V(s, 0), V(s, 1), V(s, 2));
|
||||
const Point_3 pd(V(d, 0), V(d, 1), V(d, 2));
|
||||
const Point_3 p1(V(o1, 0), V(o1, 1), V(o1, 2));
|
||||
const Point_3 p2(V(o2, 0), V(o2, 1), V(o2, 2));
|
||||
order.resize(2, 1);
|
||||
switch (CGAL::orientation(ps, pd, p1, p2))
|
||||
{
|
||||
case CGAL::POSITIVE:
|
||||
order(0, 0) = 1;
|
||||
order(1, 0) = 0;
|
||||
break;
|
||||
case CGAL::NEGATIVE:
|
||||
order(0, 0) = 0;
|
||||
order(1, 0) = 1;
|
||||
break;
|
||||
case CGAL::COPLANAR:
|
||||
{
|
||||
switch (CGAL::coplanar_orientation(ps, pd, p1, p2)) {
|
||||
case CGAL::POSITIVE:
|
||||
// Duplicated face, use index to break tie.
|
||||
order(0, 0) = adj_faces[0] < adj_faces[1] ? 0:1;
|
||||
order(1, 0) = adj_faces[0] < adj_faces[1] ? 1:0;
|
||||
break;
|
||||
case CGAL::NEGATIVE:
|
||||
// Coplanar faces, one on each side of the edge.
|
||||
// It is equally valid to order them (0, 1) or (1, 0).
|
||||
// I cannot think of any reason to prefer one to the
|
||||
// other. So just use (0, 1) ordering by default.
|
||||
order(0, 0) = 0;
|
||||
order(1, 0) = 1;
|
||||
break;
|
||||
case CGAL::COLLINEAR:
|
||||
std::cerr << "Degenerated triangle detected." <<
|
||||
std::endl;
|
||||
assert(false);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t num_adj_faces = adj_faces.size();
|
||||
const size_t o = get_opposite_vertex( get_face_index(adj_faces[0]));
|
||||
const Point_3 p_s(V(s, 0), V(s, 1), V(s, 2));
|
||||
const Point_3 p_d(V(d, 0), V(d, 1), V(d, 2));
|
||||
const Point_3 p_o(V(o, 0), V(o, 1), V(o, 2));
|
||||
const Plane_3 separator(p_s, p_d, p_o);
|
||||
if (separator.is_degenerate()) {
|
||||
throw std::runtime_error(
|
||||
"Cannot order facets around edge due to degenerated facets");
|
||||
}
|
||||
|
||||
std::vector<Point_3> opposite_vertices;
|
||||
for (size_t i=0; i<num_adj_faces; i++)
|
||||
{
|
||||
const size_t o = get_opposite_vertex( get_face_index(adj_faces[i]));
|
||||
opposite_vertices.emplace_back(
|
||||
V(o, 0), V(o, 1), V(o, 2));
|
||||
}
|
||||
|
||||
std::vector<int> positive_side;
|
||||
std::vector<int> negative_side;
|
||||
std::vector<int> tie_positive_oriented;
|
||||
std::vector<int> tie_negative_oriented;
|
||||
|
||||
std::vector<size_t> positive_side_index;
|
||||
std::vector<size_t> negative_side_index;
|
||||
std::vector<size_t> tie_positive_oriented_index;
|
||||
std::vector<size_t> tie_negative_oriented_index;
|
||||
|
||||
for (size_t i=0; i<num_adj_faces; i++)
|
||||
{
|
||||
const int f = adj_faces[i];
|
||||
const Point_3& p_a = opposite_vertices[i];
|
||||
auto orientation = separator.oriented_side(p_a);
|
||||
switch (orientation) {
|
||||
case CGAL::ON_POSITIVE_SIDE:
|
||||
positive_side.push_back(f);
|
||||
positive_side_index.push_back(i);
|
||||
break;
|
||||
case CGAL::ON_NEGATIVE_SIDE:
|
||||
negative_side.push_back(f);
|
||||
negative_side_index.push_back(i);
|
||||
break;
|
||||
case CGAL::ON_ORIENTED_BOUNDARY:
|
||||
{
|
||||
auto inplane_orientation = CGAL::coplanar_orientation(
|
||||
p_s, p_d, p_o, p_a);
|
||||
switch (inplane_orientation) {
|
||||
case CGAL::POSITIVE:
|
||||
tie_positive_oriented.push_back(f);
|
||||
tie_positive_oriented_index.push_back(i);
|
||||
break;
|
||||
case CGAL::NEGATIVE:
|
||||
tie_negative_oriented.push_back(f);
|
||||
tie_negative_oriented_index.push_back(i);
|
||||
break;
|
||||
case CGAL::COLLINEAR:
|
||||
default:
|
||||
throw std::runtime_error(
|
||||
"Degenerated facet detected.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Should not be here.
|
||||
throw std::runtime_error("Unknown CGAL state detected.");
|
||||
}
|
||||
}
|
||||
if (debug) {
|
||||
std::cout << "tie positive: " << std::endl;
|
||||
for (auto& f : tie_positive_oriented) {
|
||||
std::cout << get_face_index(f) << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::cout << "positive side: " << std::endl;
|
||||
for (auto& f : positive_side) {
|
||||
std::cout << get_face_index(f) << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::cout << "tie negative: " << std::endl;
|
||||
for (auto& f : tie_negative_oriented) {
|
||||
std::cout << get_face_index(f) << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::cout << "negative side: " << std::endl;
|
||||
for (auto& f : negative_side) {
|
||||
std::cout << get_face_index(f) << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
auto index_sort = [](std::vector<int>& data) -> std::vector<size_t>{
|
||||
const size_t len = data.size();
|
||||
std::vector<size_t> order(len);
|
||||
for (size_t i=0; i<len; i++) { order[i] = i; }
|
||||
auto comp = [&](size_t i, size_t j) { return data[i] < data[j]; };
|
||||
std::sort(order.begin(), order.end(), comp);
|
||||
return order;
|
||||
};
|
||||
|
||||
DerivedI positive_order, negative_order;
|
||||
order_facets_around_edge(V, F, s, d, positive_side, positive_order, debug);
|
||||
order_facets_around_edge(V, F, s, d, negative_side, negative_order, debug);
|
||||
std::vector<size_t> tie_positive_order = index_sort(tie_positive_oriented);
|
||||
std::vector<size_t> tie_negative_order = index_sort(tie_negative_oriented);
|
||||
|
||||
// Copy results into order vector.
|
||||
const size_t tie_positive_size = tie_positive_oriented.size();
|
||||
const size_t tie_negative_size = tie_negative_oriented.size();
|
||||
const size_t positive_size = positive_order.size();
|
||||
const size_t negative_size = negative_order.size();
|
||||
|
||||
order.resize(
|
||||
tie_positive_size + positive_size + tie_negative_size + negative_size,1);
|
||||
|
||||
size_t count=0;
|
||||
for (size_t i=0; i<tie_positive_size; i++)
|
||||
{
|
||||
order(count+i, 0) = tie_positive_oriented_index[tie_positive_order[i]];
|
||||
}
|
||||
count += tie_positive_size;
|
||||
|
||||
for (size_t i=0; i<negative_size; i++)
|
||||
{
|
||||
order(count+i, 0) = negative_side_index[negative_order(i, 0)];
|
||||
}
|
||||
count += negative_size;
|
||||
|
||||
for (size_t i=0; i<tie_negative_size; i++)
|
||||
{
|
||||
order(count+i, 0) = tie_negative_oriented_index[tie_negative_order[i]];
|
||||
}
|
||||
count += tie_negative_size;
|
||||
|
||||
for (size_t i=0; i<positive_size; i++)
|
||||
{
|
||||
order(count+i, 0) = positive_side_index[positive_order(i, 0)];
|
||||
}
|
||||
count += positive_size;
|
||||
assert(count == num_adj_faces);
|
||||
|
||||
// Find the correct start point.
|
||||
size_t start_idx = 0;
|
||||
for (size_t i=0; i<num_adj_faces; i++)
|
||||
{
|
||||
const Point_3& p_a = opposite_vertices[order(i, 0)];
|
||||
const Point_3& p_b =
|
||||
opposite_vertices[order((i+1)%num_adj_faces, 0)];
|
||||
auto orientation = CGAL::orientation(p_s, p_d, p_a, p_b);
|
||||
if (orientation == CGAL::POSITIVE)
|
||||
{
|
||||
// Angle between triangle (p_s, p_d, p_a) and (p_s, p_d, p_b) is
|
||||
// more than 180 degrees.
|
||||
start_idx = (i+1)%num_adj_faces;
|
||||
break;
|
||||
} else if (orientation == CGAL::COPLANAR &&
|
||||
Plane_3(p_s, p_d, p_a).orthogonal_direction() !=
|
||||
Plane_3(p_s, p_d, p_b).orthogonal_direction())
|
||||
{
|
||||
// All 4 points are coplanar, but p_a and p_b are on each side of
|
||||
// the edge (p_s, p_d). This means the angle between triangle
|
||||
// (p_s, p_d, p_a) and (p_s, p_d, p_b) is exactly 180 degrees.
|
||||
start_idx = (i+1)%num_adj_faces;
|
||||
break;
|
||||
}
|
||||
}
|
||||
DerivedI circular_order = order;
|
||||
for (size_t i=0; i<num_adj_faces; i++)
|
||||
{
|
||||
order(i, 0) = circular_order((start_idx + i)%num_adj_faces, 0);
|
||||
}
|
||||
}
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI>
|
||||
IGL_INLINE
|
||||
void igl::copyleft::cgal::order_facets_around_edge(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
size_t s,
|
||||
size_t d,
|
||||
const std::vector<int>& adj_faces,
|
||||
const Eigen::PlainObjectBase<DerivedV>& pivot_point,
|
||||
Eigen::PlainObjectBase<DerivedI>& order)
|
||||
{
|
||||
assert(V.cols() == 3);
|
||||
assert(F.cols() == 3);
|
||||
assert(pivot_point.cols() == 3);
|
||||
auto signed_index_to_index = [&](int signed_idx)
|
||||
{
|
||||
return abs(signed_idx) -1;
|
||||
};
|
||||
auto get_opposite_vertex_index = [&](size_t fid) -> typename DerivedF::Scalar
|
||||
{
|
||||
typedef typename DerivedF::Scalar Index;
|
||||
if (F(fid, 0) != (Index)s && F(fid, 0) != (Index)d) return F(fid, 0);
|
||||
if (F(fid, 1) != (Index)s && F(fid, 1) != (Index)d) return F(fid, 1);
|
||||
if (F(fid, 2) != (Index)s && F(fid, 2) != (Index)d) return F(fid, 2);
|
||||
assert(false);
|
||||
// avoid warning
|
||||
return -1;
|
||||
};
|
||||
|
||||
{
|
||||
// Check if s, d and pivot are collinear.
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel K;
|
||||
K::Point_3 ps(V(s,0), V(s,1), V(s,2));
|
||||
K::Point_3 pd(V(d,0), V(d,1), V(d,2));
|
||||
K::Point_3 pp(pivot_point(0,0), pivot_point(0,1), pivot_point(0,2));
|
||||
if (CGAL::collinear(ps, pd, pp)) {
|
||||
throw std::runtime_error(
|
||||
"Pivot point is collinear with the outer edge!");
|
||||
}
|
||||
}
|
||||
|
||||
const size_t N = adj_faces.size();
|
||||
const size_t num_faces = N + 1; // N adj faces + 1 pivot face
|
||||
|
||||
// Because face indices are used for tie breaking, the original face indices
|
||||
// in the new faces array must be ascending.
|
||||
auto comp = [&](int i, int j)
|
||||
{
|
||||
return signed_index_to_index(adj_faces[i]) <
|
||||
signed_index_to_index(adj_faces[j]);
|
||||
};
|
||||
std::vector<size_t> adj_order(N);
|
||||
for (size_t i=0; i<N; i++) adj_order[i] = i;
|
||||
std::sort(adj_order.begin(), adj_order.end(), comp);
|
||||
|
||||
DerivedV vertices(num_faces + 2, 3);
|
||||
for (size_t i=0; i<N; i++)
|
||||
{
|
||||
const size_t fid = signed_index_to_index(adj_faces[adj_order[i]]);
|
||||
vertices.row(i) = V.row(get_opposite_vertex_index(fid));
|
||||
}
|
||||
vertices.row(N ) = pivot_point;
|
||||
vertices.row(N+1) = V.row(s);
|
||||
vertices.row(N+2) = V.row(d);
|
||||
|
||||
DerivedF faces(num_faces, 3);
|
||||
for (size_t i=0; i<N; i++)
|
||||
{
|
||||
if (adj_faces[adj_order[i]] < 0)
|
||||
{
|
||||
faces(i,0) = N+1; // s
|
||||
faces(i,1) = N+2; // d
|
||||
faces(i,2) = i ;
|
||||
} else
|
||||
{
|
||||
faces(i,0) = N+2; // d
|
||||
faces(i,1) = N+1; // s
|
||||
faces(i,2) = i ;
|
||||
}
|
||||
}
|
||||
// Last face is the pivot face.
|
||||
faces(N, 0) = N+1;
|
||||
faces(N, 1) = N+2;
|
||||
faces(N, 2) = N;
|
||||
|
||||
std::vector<int> adj_faces_with_pivot(num_faces);
|
||||
for (size_t i=0; i<num_faces; i++)
|
||||
{
|
||||
if ((size_t)faces(i,0) == N+1 && (size_t)faces(i,1) == N+2)
|
||||
{
|
||||
adj_faces_with_pivot[i] = int(i+1) * -1;
|
||||
} else
|
||||
{
|
||||
adj_faces_with_pivot[i] = int(i+1);
|
||||
}
|
||||
}
|
||||
|
||||
DerivedI order_with_pivot;
|
||||
order_facets_around_edge(
|
||||
vertices, faces, N+1, N+2, adj_faces_with_pivot, order_with_pivot);
|
||||
|
||||
assert((size_t)order_with_pivot.size() == num_faces);
|
||||
order.resize(N);
|
||||
size_t pivot_index = num_faces + 1;
|
||||
for (size_t i=0; i<num_faces; i++)
|
||||
{
|
||||
if ((size_t)order_with_pivot[i] == N)
|
||||
{
|
||||
pivot_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(pivot_index < num_faces);
|
||||
|
||||
for (size_t i=0; i<N; i++)
|
||||
{
|
||||
order[i] = adj_order[order_with_pivot[(pivot_index+i+1)%num_faces]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, bool);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, bool);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, bool);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, bool);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#ifdef WIN32
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &, bool);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &, bool);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &, bool);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 0, -1, 3>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<double, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<double, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 0, -1, 3>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
|
||||
#endif
|
||||
#endif
|
||||
77
src/libigl/igl/copyleft/cgal/order_facets_around_edge.h
Normal file
77
src/libigl/igl/copyleft/cgal/order_facets_around_edge.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
#ifndef IGL_COPYLEFT_CGAL_ORDER_FACETS_AROUND_EDGE_H
|
||||
#define IGL_COPYLEFT_CGAL_ORDER_FACETS_AROUND_EDGE_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Given a directed edge, sort its adjacent faces. Assuming the
|
||||
// directed edge is (s, d). Sort the adjacent faces clockwise around the
|
||||
// axis (d - s), i.e. left-hand rule. An adjacent face is consistently
|
||||
// oriented if it contains (d, s) as a directed edge.
|
||||
//
|
||||
// For overlapping faces, break the tie using signed face index, smaller
|
||||
// signed index comes before the larger signed index. Signed index is
|
||||
// computed as (consistent? 1:-1) * (face_index + 1).
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertices.
|
||||
// F #F by 3 list of faces
|
||||
// s Index of source vertex.
|
||||
// d Index of destination vertex.
|
||||
// adj_faces List of adjacent face signed indices.
|
||||
// Output:
|
||||
// order List of face indices that orders adjacent faces around edge
|
||||
// (s, d) clockwise.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI >
|
||||
IGL_INLINE
|
||||
void order_facets_around_edge(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
size_t s,
|
||||
size_t d,
|
||||
const std::vector<int>& adj_faces,
|
||||
Eigen::PlainObjectBase<DerivedI>& order,
|
||||
bool debug=false);
|
||||
|
||||
// This function is a wrapper around the one above. Since the ordering
|
||||
// is circular, the pivot point is used to define a starting point. So
|
||||
// order[0] is the index into adj_face that is immediately after the
|
||||
// pivot face (s, d, pivot point) in clockwise order.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI>
|
||||
IGL_INLINE
|
||||
void order_facets_around_edge(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
size_t s,
|
||||
size_t d,
|
||||
const std::vector<int>& adj_faces,
|
||||
const Eigen::PlainObjectBase<DerivedV>& pivot_point,
|
||||
Eigen::PlainObjectBase<DerivedI>& order);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
#include "order_facets_around_edge.cpp"
|
||||
#endif
|
||||
#endif
|
||||
332
src/libigl/igl/copyleft/cgal/order_facets_around_edges.cpp
Normal file
332
src/libigl/igl/copyleft/cgal/order_facets_around_edges.cpp
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "order_facets_around_edges.h"
|
||||
#include "order_facets_around_edge.h"
|
||||
#include "../../sort_angles.h"
|
||||
#include <Eigen/Geometry>
|
||||
#include <type_traits>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedN,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename uE2oEType,
|
||||
typename uE2CType >
|
||||
IGL_INLINE
|
||||
typename std::enable_if<!std::is_same<typename DerivedV::Scalar,
|
||||
typename CGAL::Exact_predicates_exact_constructions_kernel::FT>::value, void>::type
|
||||
igl::copyleft::cgal::order_facets_around_edges(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedN>& N,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
std::vector<std::vector<uE2oEType> >& uE2oE,
|
||||
std::vector<std::vector<uE2CType > >& uE2C ) {
|
||||
|
||||
typedef Eigen::Matrix<typename DerivedN::Scalar, 3, 1> Vector3F;
|
||||
const typename DerivedV::Scalar EPS = 1e-12;
|
||||
const size_t num_faces = F.rows();
|
||||
const size_t num_undirected_edges = uE.rows();
|
||||
|
||||
auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; };
|
||||
auto edge_index_to_corner_index = [&](size_t ei) { return ei / num_faces; };
|
||||
|
||||
uE2oE.resize(num_undirected_edges);
|
||||
uE2C.resize(num_undirected_edges);
|
||||
|
||||
for(size_t ui = 0;ui<num_undirected_edges;ui++)
|
||||
{
|
||||
const auto& adj_edges = uE2E[ui];
|
||||
const size_t edge_valance = adj_edges.size();
|
||||
assert(edge_valance > 0);
|
||||
|
||||
const auto ref_edge = adj_edges[0];
|
||||
const auto ref_face = edge_index_to_face_index(ref_edge);
|
||||
Vector3F ref_normal = N.row(ref_face);
|
||||
|
||||
const auto ref_corner_o = edge_index_to_corner_index(ref_edge);
|
||||
const auto ref_corner_s = (ref_corner_o+1)%3;
|
||||
const auto ref_corner_d = (ref_corner_o+2)%3;
|
||||
|
||||
const typename DerivedF::Scalar o = F(ref_face, ref_corner_o);
|
||||
const typename DerivedF::Scalar s = F(ref_face, ref_corner_s);
|
||||
const typename DerivedF::Scalar d = F(ref_face, ref_corner_d);
|
||||
|
||||
Vector3F edge = V.row(d) - V.row(s);
|
||||
auto edge_len = edge.norm();
|
||||
bool degenerated = edge_len < EPS;
|
||||
if (degenerated) {
|
||||
if (edge_valance <= 2) {
|
||||
// There is only one way to order 2 or less faces.
|
||||
edge.setZero();
|
||||
} else {
|
||||
edge.setZero();
|
||||
Eigen::Matrix<typename DerivedN::Scalar, Eigen::Dynamic, 3>
|
||||
normals(edge_valance, 3);
|
||||
for (size_t fei=0; fei<edge_valance; fei++) {
|
||||
const auto fe = adj_edges[fei];
|
||||
const auto f = edge_index_to_face_index(fe);
|
||||
normals.row(fei) = N.row(f);
|
||||
}
|
||||
for (size_t i=0; i<edge_valance; i++) {
|
||||
size_t j = (i+1) % edge_valance;
|
||||
Vector3F ni = normals.row(i);
|
||||
Vector3F nj = normals.row(j);
|
||||
edge = ni.cross(nj);
|
||||
edge_len = edge.norm();
|
||||
if (edge_len >= EPS) {
|
||||
edge.normalize();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure edge direction are consistent with reference face.
|
||||
Vector3F in_face_vec = V.row(o) - V.row(s);
|
||||
if (edge.cross(in_face_vec).dot(ref_normal) < 0) {
|
||||
edge *= -1;
|
||||
}
|
||||
|
||||
if (edge.norm() < EPS) {
|
||||
std::cerr << "=====================================" << std::endl;
|
||||
std::cerr << " ui: " << ui << std::endl;
|
||||
std::cerr << "edge: " << ref_edge << std::endl;
|
||||
std::cerr << "face: " << ref_face << std::endl;
|
||||
std::cerr << " vs: " << V.row(s) << std::endl;
|
||||
std::cerr << " vd: " << V.row(d) << std::endl;
|
||||
std::cerr << "adj face normals: " << std::endl;
|
||||
std::cerr << normals << std::endl;
|
||||
std::cerr << "Very degenerated case detected:" << std::endl;
|
||||
std::cerr << "Near zero edge surrounded by "
|
||||
<< edge_valance << " neearly colinear faces" <<
|
||||
std::endl;
|
||||
std::cerr << "=====================================" << std::endl;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
edge.normalize();
|
||||
}
|
||||
|
||||
Eigen::MatrixXd angle_data(edge_valance, 3);
|
||||
std::vector<bool> cons(edge_valance);
|
||||
|
||||
for (size_t fei=0; fei<edge_valance; fei++) {
|
||||
const auto fe = adj_edges[fei];
|
||||
const auto f = edge_index_to_face_index(fe);
|
||||
const auto c = edge_index_to_corner_index(fe);
|
||||
cons[fei] = (d == F(f, (c+1)%3));
|
||||
assert( cons[fei] || (d == F(f,(c+2)%3)));
|
||||
assert(!cons[fei] || (s == F(f,(c+2)%3)));
|
||||
assert(!cons[fei] || (d == F(f,(c+1)%3)));
|
||||
Vector3F n = N.row(f);
|
||||
angle_data(fei, 0) = ref_normal.cross(n).dot(edge);
|
||||
angle_data(fei, 1) = ref_normal.dot(n);
|
||||
if (cons[fei]) {
|
||||
angle_data(fei, 0) *= -1;
|
||||
angle_data(fei, 1) *= -1;
|
||||
}
|
||||
angle_data(fei, 0) *= -1; // Sort clockwise.
|
||||
angle_data(fei, 2) = (cons[fei]?1.:-1.)*(f+1);
|
||||
}
|
||||
|
||||
Eigen::VectorXi order;
|
||||
igl::sort_angles(angle_data, order);
|
||||
|
||||
auto& ordered_edges = uE2oE[ui];
|
||||
auto& consistency = uE2C[ui];
|
||||
|
||||
ordered_edges.resize(edge_valance);
|
||||
consistency.resize(edge_valance);
|
||||
for (size_t fei=0; fei<edge_valance; fei++) {
|
||||
ordered_edges[fei] = adj_edges[order[fei]];
|
||||
consistency[fei] = cons[order[fei]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedN,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename uE2oEType,
|
||||
typename uE2CType >
|
||||
IGL_INLINE
|
||||
typename std::enable_if<std::is_same<typename DerivedV::Scalar,
|
||||
typename CGAL::Exact_predicates_exact_constructions_kernel::FT>::value, void>::type
|
||||
igl::copyleft::cgal::order_facets_around_edges(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedN>& N,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
std::vector<std::vector<uE2oEType> >& uE2oE,
|
||||
std::vector<std::vector<uE2CType > >& uE2C ) {
|
||||
|
||||
typedef Eigen::Matrix<typename DerivedN::Scalar, 3, 1> Vector3F;
|
||||
typedef Eigen::Matrix<typename DerivedV::Scalar, 3, 1> Vector3E;
|
||||
const typename DerivedV::Scalar EPS = 1e-12;
|
||||
const size_t num_faces = F.rows();
|
||||
const size_t num_undirected_edges = uE.rows();
|
||||
|
||||
auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; };
|
||||
auto edge_index_to_corner_index = [&](size_t ei) { return ei / num_faces; };
|
||||
|
||||
uE2oE.resize(num_undirected_edges);
|
||||
uE2C.resize(num_undirected_edges);
|
||||
|
||||
for(size_t ui = 0;ui<num_undirected_edges;ui++)
|
||||
{
|
||||
const auto& adj_edges = uE2E[ui];
|
||||
const size_t edge_valance = adj_edges.size();
|
||||
assert(edge_valance > 0);
|
||||
|
||||
const auto ref_edge = adj_edges[0];
|
||||
const auto ref_face = edge_index_to_face_index(ref_edge);
|
||||
Vector3F ref_normal = N.row(ref_face);
|
||||
|
||||
const auto ref_corner_o = edge_index_to_corner_index(ref_edge);
|
||||
const auto ref_corner_s = (ref_corner_o+1)%3;
|
||||
const auto ref_corner_d = (ref_corner_o+2)%3;
|
||||
|
||||
const typename DerivedF::Scalar o = F(ref_face, ref_corner_o);
|
||||
const typename DerivedF::Scalar s = F(ref_face, ref_corner_s);
|
||||
const typename DerivedF::Scalar d = F(ref_face, ref_corner_d);
|
||||
|
||||
Vector3E exact_edge = V.row(d) - V.row(s);
|
||||
exact_edge.array() /= exact_edge.squaredNorm();
|
||||
Vector3F edge(
|
||||
CGAL::to_double(exact_edge[0]),
|
||||
CGAL::to_double(exact_edge[1]),
|
||||
CGAL::to_double(exact_edge[2]));
|
||||
edge.normalize();
|
||||
|
||||
Eigen::MatrixXd angle_data(edge_valance, 3);
|
||||
std::vector<bool> cons(edge_valance);
|
||||
|
||||
for (size_t fei=0; fei<edge_valance; fei++) {
|
||||
const auto fe = adj_edges[fei];
|
||||
const auto f = edge_index_to_face_index(fe);
|
||||
const auto c = edge_index_to_corner_index(fe);
|
||||
cons[fei] = (d == F(f, (c+1)%3));
|
||||
assert( cons[fei] || (d == F(f,(c+2)%3)));
|
||||
assert(!cons[fei] || (s == F(f,(c+2)%3)));
|
||||
assert(!cons[fei] || (d == F(f,(c+1)%3)));
|
||||
Vector3F n = N.row(f);
|
||||
angle_data(fei, 0) = ref_normal.cross(n).dot(edge);
|
||||
angle_data(fei, 1) = ref_normal.dot(n);
|
||||
if (cons[fei]) {
|
||||
angle_data(fei, 0) *= -1;
|
||||
angle_data(fei, 1) *= -1;
|
||||
}
|
||||
angle_data(fei, 0) *= -1; // Sort clockwise.
|
||||
angle_data(fei, 2) = (cons[fei]?1.:-1.)*(f+1);
|
||||
}
|
||||
|
||||
Eigen::VectorXi order;
|
||||
igl::sort_angles(angle_data, order);
|
||||
|
||||
auto& ordered_edges = uE2oE[ui];
|
||||
auto& consistency = uE2C[ui];
|
||||
|
||||
ordered_edges.resize(edge_valance);
|
||||
consistency.resize(edge_valance);
|
||||
for (size_t fei=0; fei<edge_valance; fei++) {
|
||||
ordered_edges[fei] = adj_edges[order[fei]];
|
||||
consistency[fei] = cons[order[fei]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename uE2oEType,
|
||||
typename uE2CType >
|
||||
IGL_INLINE void igl::copyleft::cgal::order_facets_around_edges(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
std::vector<std::vector<uE2oEType> >& uE2oE,
|
||||
std::vector<std::vector<uE2CType > >& uE2C ) {
|
||||
|
||||
//typedef Eigen::Matrix<typename DerivedV::Scalar, 3, 1> Vector3E;
|
||||
const size_t num_faces = F.rows();
|
||||
const size_t num_undirected_edges = uE.rows();
|
||||
|
||||
auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; };
|
||||
auto edge_index_to_corner_index = [&](size_t ei) { return ei / num_faces; };
|
||||
|
||||
uE2oE.resize(num_undirected_edges);
|
||||
uE2C.resize(num_undirected_edges);
|
||||
|
||||
for(size_t ui = 0;ui<num_undirected_edges;ui++)
|
||||
{
|
||||
const auto& adj_edges = uE2E[ui];
|
||||
const size_t edge_valance = adj_edges.size();
|
||||
assert(edge_valance > 0);
|
||||
|
||||
const auto ref_edge = adj_edges[0];
|
||||
const auto ref_face = edge_index_to_face_index(ref_edge);
|
||||
|
||||
const auto ref_corner_o = edge_index_to_corner_index(ref_edge);
|
||||
const auto ref_corner_s = (ref_corner_o+1)%3;
|
||||
const auto ref_corner_d = (ref_corner_o+2)%3;
|
||||
|
||||
//const typename DerivedF::Scalar o = F(ref_face, ref_corner_o);
|
||||
const typename DerivedF::Scalar s = F(ref_face, ref_corner_s);
|
||||
const typename DerivedF::Scalar d = F(ref_face, ref_corner_d);
|
||||
|
||||
std::vector<bool> cons(edge_valance);
|
||||
std::vector<int> adj_faces(edge_valance);
|
||||
for (size_t fei=0; fei<edge_valance; fei++) {
|
||||
const auto fe = adj_edges[fei];
|
||||
const auto f = edge_index_to_face_index(fe);
|
||||
const auto c = edge_index_to_corner_index(fe);
|
||||
cons[fei] = (d == F(f, (c+1)%3));
|
||||
adj_faces[fei] = (f+1) * (cons[fei] ? 1:-1);
|
||||
|
||||
assert( cons[fei] || (d == F(f,(c+2)%3)));
|
||||
assert(!cons[fei] || (s == F(f,(c+2)%3)));
|
||||
assert(!cons[fei] || (d == F(f,(c+1)%3)));
|
||||
}
|
||||
|
||||
Eigen::VectorXi order;
|
||||
order_facets_around_edge(V, F, s, d, adj_faces, order);
|
||||
assert((size_t)order.size() == edge_valance);
|
||||
|
||||
auto& ordered_edges = uE2oE[ui];
|
||||
auto& consistency = uE2C[ui];
|
||||
|
||||
ordered_edges.resize(edge_valance);
|
||||
consistency.resize(edge_valance);
|
||||
for (size_t fei=0; fei<edge_valance; fei++) {
|
||||
ordered_edges[fei] = adj_edges[order[fei]];
|
||||
consistency[fei] = cons[order[fei]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::order_facets_around_edges<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int, int, bool>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > >&);
|
||||
// generated by autoexplicit.sh
|
||||
template std::enable_if<!(std::is_same<Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, CGAL::Lazy_exact_nt<CGAL::Gmpq> >::value), void>::type igl::copyleft::cgal::order_facets_around_edges<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int, int, bool>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > >&);
|
||||
template void igl::copyleft::cgal::order_facets_around_edges<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, long, long, bool>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&, std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > >&);
|
||||
template void igl::copyleft::cgal::order_facets_around_edges<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, long, long, bool>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&, std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > >&);
|
||||
template void igl::copyleft::cgal::order_facets_around_edges<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, long, long, bool>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&, std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > >&);
|
||||
template void igl::copyleft::cgal::order_facets_around_edges<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, long, long, bool>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&, std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > >&);
|
||||
#endif
|
||||
107
src/libigl/igl/copyleft/cgal/order_facets_around_edges.h
Normal file
107
src/libigl/igl/copyleft/cgal/order_facets_around_edges.h
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_ORDER_FACETS_AROUND_EDGES_H
|
||||
#define IGL_COPYLEFT_CGAL_ORDER_FACETS_AROUND_EDGES_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <vector>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// For each undirected edge, sort its adjacent faces. Assuming the
|
||||
// undirected edge is (s, d). Sort the adjacent faces clockwise around the
|
||||
// axis (d - s), i.e. left-hand rule. An adjacent face is consistently
|
||||
// oriented if it contains (d, s) as a directed edge.
|
||||
//
|
||||
// For overlapping faces, break the tie using signed face index, smaller
|
||||
// signed index comes before the larger signed index. Signed index is
|
||||
// computed as (consistent? 1:-1) * index.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertices.
|
||||
// F #F by 3 list of faces
|
||||
// N #F by 3 list of face normals.
|
||||
// uE #uE by 2 list of vertex_indices, represents undirected edges.
|
||||
// uE2E #uE list of lists that maps uE to E. (a one-to-many map)
|
||||
//
|
||||
// Outputs:
|
||||
// uE2oE #uE list of lists that maps uE to an ordered list of E. (a
|
||||
// one-to-many map)
|
||||
// uE2C #uE list of lists of bools indicates whether each face in
|
||||
// uE2oE[i] is consistently orientated as the ordering.
|
||||
//
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedN,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename uE2oEType,
|
||||
typename uE2CType >
|
||||
IGL_INLINE
|
||||
typename std::enable_if<!std::is_same<typename DerivedV::Scalar,
|
||||
typename CGAL::Exact_predicates_exact_constructions_kernel::FT>::value, void>::type
|
||||
order_facets_around_edges(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedN>& N,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
std::vector<std::vector<uE2oEType> >& uE2oE,
|
||||
std::vector<std::vector<uE2CType > >& uE2C );
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedN,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename uE2oEType,
|
||||
typename uE2CType >
|
||||
IGL_INLINE
|
||||
typename std::enable_if<std::is_same<typename DerivedV::Scalar,
|
||||
typename CGAL::Exact_predicates_exact_constructions_kernel::FT>::value, void>::type
|
||||
order_facets_around_edges(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedN>& N,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
std::vector<std::vector<uE2oEType> >& uE2oE,
|
||||
std::vector<std::vector<uE2CType > >& uE2C );
|
||||
|
||||
// Order faces around each edge. Only exact predicate is used in the algorithm.
|
||||
// Normal is not needed.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename uE2oEType,
|
||||
typename uE2CType >
|
||||
IGL_INLINE void order_facets_around_edges(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
std::vector<std::vector<uE2oEType> >& uE2oE,
|
||||
std::vector<std::vector<uE2CType > >& uE2C );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
#include "order_facets_around_edges.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
37
src/libigl/igl/copyleft/cgal/orient2D.cpp
Normal file
37
src/libigl/igl/copyleft/cgal/orient2D.cpp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "orient2D.h"
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
template<typename Scalar>
|
||||
IGL_INLINE short igl::copyleft::cgal::orient2D(
|
||||
const Scalar pa[2],
|
||||
const Scalar pb[2],
|
||||
const Scalar pc[2])
|
||||
{
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Epeck;
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Epick;
|
||||
typedef typename std::conditional<std::is_same<Scalar, Epeck::FT>::value,
|
||||
Epeck, Epick>::type Kernel;
|
||||
|
||||
switch(CGAL::orientation(
|
||||
typename Kernel::Point_2(pa[0], pa[1]),
|
||||
typename Kernel::Point_2(pb[0], pb[1]),
|
||||
typename Kernel::Point_2(pc[0], pc[1]))) {
|
||||
case CGAL::LEFT_TURN:
|
||||
return 1;
|
||||
case CGAL::RIGHT_TURN:
|
||||
return -1;
|
||||
case CGAL::COLLINEAR:
|
||||
return 0;
|
||||
default:
|
||||
throw "Invalid orientation";
|
||||
}
|
||||
}
|
||||
38
src/libigl/igl/copyleft/cgal/orient2D.h
Normal file
38
src/libigl/igl/copyleft/cgal/orient2D.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef IGL_COPYLEFT_CGAL_ORIENT_2D_H
|
||||
#define IGL_COPYLEFT_CGAL_ORIENT_2D_H
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Inputs:
|
||||
// pa,pb,pc 2D points.
|
||||
// Output:
|
||||
// 1 if pa,pb,pc are counterclockwise oriented.
|
||||
// 0 if pa,pb,pc are counterclockwise oriented.
|
||||
// -1 if pa,pb,pc are clockwise oriented.
|
||||
template <typename Scalar>
|
||||
IGL_INLINE short orient2D(
|
||||
const Scalar pa[2],
|
||||
const Scalar pb[2],
|
||||
const Scalar pc[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "orient2D.cpp"
|
||||
#endif
|
||||
#endif
|
||||
39
src/libigl/igl/copyleft/cgal/orient3D.cpp
Normal file
39
src/libigl/igl/copyleft/cgal/orient3D.cpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "orient3D.h"
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
template<typename Scalar>
|
||||
IGL_INLINE short igl::copyleft::cgal::orient3D(
|
||||
const Scalar pa[3],
|
||||
const Scalar pb[3],
|
||||
const Scalar pc[3],
|
||||
const Scalar pd[3])
|
||||
{
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Epeck;
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Epick;
|
||||
typedef typename std::conditional<std::is_same<Scalar, Epeck::FT>::value,
|
||||
Epeck, Epick>::type Kernel;
|
||||
|
||||
switch(CGAL::orientation(
|
||||
typename Kernel::Point_3(pa[0], pa[1], pa[2]),
|
||||
typename Kernel::Point_3(pb[0], pb[1], pb[2]),
|
||||
typename Kernel::Point_3(pc[0], pc[1], pc[2]),
|
||||
typename Kernel::Point_3(pd[0], pd[1], pd[2]))) {
|
||||
case CGAL::POSITIVE:
|
||||
return 1;
|
||||
case CGAL::NEGATIVE:
|
||||
return -1;
|
||||
case CGAL::COPLANAR:
|
||||
return 0;
|
||||
default:
|
||||
throw "Invalid orientation";
|
||||
}
|
||||
}
|
||||
39
src/libigl/igl/copyleft/cgal/orient3D.h
Normal file
39
src/libigl/igl/copyleft/cgal/orient3D.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef IGL_COPYLEFT_CGAL_ORIENT_3D_H
|
||||
#define IGL_COPYLEFT_CGAL_ORIENT_3D_H
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Inputs:
|
||||
// pa,pb,pc,pd 3D points.
|
||||
// Output:
|
||||
// 1 if pa,pb,pc,pd forms a tet of positive volume.
|
||||
// 0 if pa,pb,pc,pd are coplanar.
|
||||
// -1 if pa,pb,pc,pd forms a tet of negative volume.
|
||||
template <typename Scalar>
|
||||
IGL_INLINE short orient3D(
|
||||
const Scalar pa[3],
|
||||
const Scalar pb[3],
|
||||
const Scalar pc[3],
|
||||
const Scalar pd[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "orient3D.cpp"
|
||||
#endif
|
||||
#endif
|
||||
232
src/libigl/igl/copyleft/cgal/outer_element.cpp
Normal file
232
src/libigl/igl/copyleft/cgal/outer_element.cpp
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "outer_element.h"
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename IndexType,
|
||||
typename DerivedA
|
||||
>
|
||||
IGL_INLINE void igl::copyleft::cgal::outer_vertex(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
const Eigen::PlainObjectBase<DerivedI> & I,
|
||||
IndexType & v_index,
|
||||
Eigen::PlainObjectBase<DerivedA> & A)
|
||||
{
|
||||
// Algorithm:
|
||||
// Find an outer vertex (i.e. vertex reachable from infinity)
|
||||
// Return the vertex with the largest X value.
|
||||
// If there is a tie, pick the one with largest Y value.
|
||||
// If there is still a tie, pick the one with the largest Z value.
|
||||
// If there is still a tie, then there are duplicated vertices within the
|
||||
// mesh, which violates the precondition.
|
||||
typedef typename DerivedF::Scalar Index;
|
||||
const Index INVALID = std::numeric_limits<Index>::max();
|
||||
const size_t num_selected_faces = I.rows();
|
||||
std::vector<size_t> candidate_faces;
|
||||
Index outer_vid = INVALID;
|
||||
typename DerivedV::Scalar outer_val = 0;
|
||||
for (size_t i=0; i<num_selected_faces; i++)
|
||||
{
|
||||
size_t f = I(i);
|
||||
for (size_t j=0; j<3; j++)
|
||||
{
|
||||
Index v = F(f, j);
|
||||
auto vx = V(v, 0);
|
||||
if (outer_vid == INVALID || vx > outer_val)
|
||||
{
|
||||
outer_val = vx;
|
||||
outer_vid = v;
|
||||
candidate_faces = {f};
|
||||
} else if (v == outer_vid)
|
||||
{
|
||||
candidate_faces.push_back(f);
|
||||
} else if (vx == outer_val)
|
||||
{
|
||||
// Break tie.
|
||||
auto vy = V(v,1);
|
||||
auto vz = V(v, 2);
|
||||
auto outer_y = V(outer_vid, 1);
|
||||
auto outer_z = V(outer_vid, 2);
|
||||
assert(!(vy == outer_y && vz == outer_z));
|
||||
bool replace = (vy > outer_y) ||
|
||||
((vy == outer_y) && (vz > outer_z));
|
||||
if (replace)
|
||||
{
|
||||
outer_val = vx;
|
||||
outer_vid = v;
|
||||
candidate_faces = {f};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(outer_vid != INVALID);
|
||||
assert(candidate_faces.size() > 0);
|
||||
v_index = outer_vid;
|
||||
A.resize(candidate_faces.size());
|
||||
std::copy(candidate_faces.begin(), candidate_faces.end(), A.data());
|
||||
}
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename IndexType,
|
||||
typename DerivedA
|
||||
>
|
||||
IGL_INLINE void igl::copyleft::cgal::outer_edge(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
const Eigen::PlainObjectBase<DerivedI> & I,
|
||||
IndexType & v1,
|
||||
IndexType & v2,
|
||||
Eigen::PlainObjectBase<DerivedA> & A) {
|
||||
// Algorithm:
|
||||
// Find an outer vertex first.
|
||||
// Find the incident edge with largest abs slope when projected onto XY plane.
|
||||
// If there is a tie, check the signed slope and use the positive one.
|
||||
// If there is still a tie, break it using the projected slope onto ZX plane.
|
||||
// If there is still a tie, again check the signed slope and use the positive one.
|
||||
// If there is still a tie, then there are multiple overlapping edges,
|
||||
// which violates the precondition.
|
||||
typedef typename DerivedV::Scalar Scalar;
|
||||
typedef typename DerivedV::Index Index;
|
||||
typedef typename Eigen::Matrix<Scalar, 3, 1> ScalarArray3;
|
||||
typedef typename Eigen::Matrix<typename DerivedF::Scalar, 3, 1> IndexArray3;
|
||||
const Index INVALID = std::numeric_limits<Index>::max();
|
||||
|
||||
Index outer_vid;
|
||||
Eigen::Matrix<Index,Eigen::Dynamic,1> candidate_faces;
|
||||
outer_vertex(V, F, I, outer_vid, candidate_faces);
|
||||
const ScalarArray3& outer_v = V.row(outer_vid);
|
||||
assert(candidate_faces.size() > 0);
|
||||
|
||||
auto get_vertex_index = [&](const IndexArray3& f, Index vid) -> Index
|
||||
{
|
||||
if (f[0] == vid) return 0;
|
||||
if (f[1] == vid) return 1;
|
||||
if (f[2] == vid) return 2;
|
||||
assert(false);
|
||||
return -1;
|
||||
};
|
||||
|
||||
auto unsigned_value = [](Scalar v) -> Scalar {
|
||||
if (v < 0) return v * -1;
|
||||
else return v;
|
||||
};
|
||||
|
||||
Scalar outer_slope_YX = 0;
|
||||
Scalar outer_slope_ZX = 0;
|
||||
Index outer_opp_vid = INVALID;
|
||||
bool infinite_slope_detected = false;
|
||||
std::vector<Index> incident_faces;
|
||||
auto check_and_update_outer_edge = [&](Index opp_vid, Index fid) -> void {
|
||||
if (opp_vid == outer_opp_vid)
|
||||
{
|
||||
incident_faces.push_back(fid);
|
||||
return;
|
||||
}
|
||||
|
||||
const ScalarArray3 opp_v = V.row(opp_vid);
|
||||
if (!infinite_slope_detected && outer_v[0] != opp_v[0])
|
||||
{
|
||||
// Finite slope
|
||||
const ScalarArray3 diff = opp_v - outer_v;
|
||||
const Scalar slope_YX = diff[1] / diff[0];
|
||||
const Scalar slope_ZX = diff[2] / diff[0];
|
||||
const Scalar u_slope_YX = unsigned_value(slope_YX);
|
||||
const Scalar u_slope_ZX = unsigned_value(slope_ZX);
|
||||
bool update = false;
|
||||
if (outer_opp_vid == INVALID) {
|
||||
update = true;
|
||||
} else {
|
||||
const Scalar u_outer_slope_YX = unsigned_value(outer_slope_YX);
|
||||
if (u_slope_YX > u_outer_slope_YX) {
|
||||
update = true;
|
||||
} else if (u_slope_YX == u_outer_slope_YX &&
|
||||
slope_YX > outer_slope_YX) {
|
||||
update = true;
|
||||
} else if (slope_YX == outer_slope_YX) {
|
||||
const Scalar u_outer_slope_ZX =
|
||||
unsigned_value(outer_slope_ZX);
|
||||
if (u_slope_ZX > u_outer_slope_ZX) {
|
||||
update = true;
|
||||
} else if (u_slope_ZX == u_outer_slope_ZX &&
|
||||
slope_ZX > outer_slope_ZX) {
|
||||
update = true;
|
||||
} else if (slope_ZX == u_outer_slope_ZX) {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (update) {
|
||||
outer_opp_vid = opp_vid;
|
||||
outer_slope_YX = slope_YX;
|
||||
outer_slope_ZX = slope_ZX;
|
||||
incident_faces = {fid};
|
||||
}
|
||||
} else if (!infinite_slope_detected)
|
||||
{
|
||||
// Infinite slope
|
||||
outer_opp_vid = opp_vid;
|
||||
infinite_slope_detected = true;
|
||||
incident_faces = {fid};
|
||||
}
|
||||
};
|
||||
|
||||
const size_t num_candidate_faces = candidate_faces.size();
|
||||
for (size_t i=0; i<num_candidate_faces; i++)
|
||||
{
|
||||
const Index fid = candidate_faces(i);
|
||||
const IndexArray3& f = F.row(fid);
|
||||
size_t id = get_vertex_index(f, outer_vid);
|
||||
Index next_vid = f((id+1)%3);
|
||||
Index prev_vid = f((id+2)%3);
|
||||
check_and_update_outer_edge(next_vid, fid);
|
||||
check_and_update_outer_edge(prev_vid, fid);
|
||||
}
|
||||
|
||||
v1 = outer_vid;
|
||||
v2 = outer_opp_vid;
|
||||
A.resize(incident_faces.size());
|
||||
std::copy(incident_faces.begin(), incident_faces.end(), A.data());
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 1, -1, -1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 1, -1, -1> > const&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
|
||||
#ifdef WIN32
|
||||
template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<long, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<long, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, 3, 0, -1, 3>, class Eigen::Matrix<long, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<long, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<double, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<double, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<double, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 1, -1, -1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 1, -1, -1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
|
||||
template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<double, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, 3, 0, -1, 3>, class Eigen::Matrix<long, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<long, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
|
||||
#endif
|
||||
#endif
|
||||
83
src/libigl/igl/copyleft/cgal/outer_element.h
Normal file
83
src/libigl/igl/copyleft/cgal/outer_element.h
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_OUTER_ELEMENT_H
|
||||
#define IGL_COPYLEFT_CGAL_OUTER_ELEMENT_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Find a vertex that is reachable from infinite without crossing any faces.
|
||||
// Such vertex is called "outer vertex."
|
||||
//
|
||||
// Precondition: The input mesh must have all self-intersection resolved and
|
||||
// no duplicated vertices. See cgal::remesh_self_intersections.h for how to
|
||||
// obtain such input.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices into V
|
||||
// I #I list of facets to consider
|
||||
// Outputs:
|
||||
// v_index index of outer vertex
|
||||
// A #A list of facets incident to the outer vertex
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename IndexType,
|
||||
typename DerivedA
|
||||
>
|
||||
IGL_INLINE void outer_vertex(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
const Eigen::PlainObjectBase<DerivedI> & I,
|
||||
IndexType & v_index,
|
||||
Eigen::PlainObjectBase<DerivedA> & A);
|
||||
// Find an edge that is reachable from infinity without crossing any faces.
|
||||
// Such edge is called "outer edge."
|
||||
//
|
||||
// Precondition: The input mesh must have all self-intersection resolved
|
||||
// and no duplicated vertices. The correctness of the output depends on
|
||||
// the fact that there is no edge overlap. See
|
||||
// cgal::remesh_self_intersections.h for how to obtain such input.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices into V
|
||||
// I #I list of facets to consider
|
||||
// Outputs:
|
||||
// v1 index of the first end point of outer edge
|
||||
// v2 index of the second end point of outer edge
|
||||
// A #A list of facets incident to the outer edge
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename IndexType,
|
||||
typename DerivedA
|
||||
>
|
||||
IGL_INLINE void outer_edge(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
const Eigen::PlainObjectBase<DerivedI> & I,
|
||||
IndexType & v1,
|
||||
IndexType & v2,
|
||||
Eigen::PlainObjectBase<DerivedA> & A);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "outer_element.cpp"
|
||||
#endif
|
||||
#endif
|
||||
180
src/libigl/igl/copyleft/cgal/outer_facet.cpp
Normal file
180
src/libigl/igl/copyleft/cgal/outer_facet.cpp
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "outer_facet.h"
|
||||
#include "outer_element.h"
|
||||
#include "order_facets_around_edge.h"
|
||||
#include <algorithm>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename IndexType
|
||||
>
|
||||
IGL_INLINE void igl::copyleft::cgal::outer_facet(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
const Eigen::PlainObjectBase<DerivedI> & I,
|
||||
IndexType & f,
|
||||
bool & flipped) {
|
||||
|
||||
// Algorithm:
|
||||
//
|
||||
// 1. Find an outer edge (s, d).
|
||||
//
|
||||
// 2. Order adjacent facets around this edge. Because the edge is an
|
||||
// outer edge, there exists a plane passing through it such that all its
|
||||
// adjacent facets lie on the same side. The implementation of
|
||||
// order_facets_around_edge() will find a natural start facet such that
|
||||
// The first and last facets according to this order are on the outside.
|
||||
//
|
||||
// 3. Because the vertex s is an outer vertex by construction (see
|
||||
// implemnetation of outer_edge()). The first adjacent facet is facing
|
||||
// outside (i.e. flipped=false) if it has positive X normal component.
|
||||
// If it has zero normal component, it is facing outside if it contains
|
||||
// directed edge (s, d).
|
||||
|
||||
//typedef typename DerivedV::Scalar Scalar;
|
||||
typedef typename DerivedV::Index Index;
|
||||
|
||||
Index s,d;
|
||||
Eigen::Matrix<Index,Eigen::Dynamic,1> incident_faces;
|
||||
outer_edge(V, F, I, s, d, incident_faces);
|
||||
assert(incident_faces.size() > 0);
|
||||
|
||||
auto convert_to_signed_index = [&](size_t fid) -> int{
|
||||
if ((F(fid, 0) == s && F(fid, 1) == d) ||
|
||||
(F(fid, 1) == s && F(fid, 2) == d) ||
|
||||
(F(fid, 2) == s && F(fid, 0) == d) ) {
|
||||
return int(fid+1) * -1;
|
||||
} else {
|
||||
return int(fid+1);
|
||||
}
|
||||
};
|
||||
|
||||
auto signed_index_to_index = [&](int signed_id) -> size_t {
|
||||
return size_t(abs(signed_id) - 1);
|
||||
};
|
||||
|
||||
std::vector<int> adj_faces(incident_faces.size());
|
||||
std::transform(incident_faces.data(),
|
||||
incident_faces.data() + incident_faces.size(),
|
||||
adj_faces.begin(),
|
||||
convert_to_signed_index);
|
||||
|
||||
DerivedV pivot_point = V.row(s);
|
||||
pivot_point(0, 0) += 1.0;
|
||||
|
||||
Eigen::VectorXi order;
|
||||
order_facets_around_edge(V, F, s, d, adj_faces, pivot_point, order);
|
||||
|
||||
f = signed_index_to_index(adj_faces[order[0]]);
|
||||
flipped = adj_faces[order[0]] > 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedN,
|
||||
typename DerivedI,
|
||||
typename IndexType
|
||||
>
|
||||
IGL_INLINE void igl::copyleft::cgal::outer_facet(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
const Eigen::PlainObjectBase<DerivedN> & N,
|
||||
const Eigen::PlainObjectBase<DerivedI> & I,
|
||||
IndexType & f,
|
||||
bool & flipped) {
|
||||
// Algorithm:
|
||||
// Find an outer edge.
|
||||
// Find the incident facet with the largest absolute X normal component.
|
||||
// If there is a tie, keep the one with positive X component.
|
||||
// If there is still a tie, pick the face with the larger signed index
|
||||
// (flipped face has negative index).
|
||||
typedef typename DerivedV::Scalar Scalar;
|
||||
typedef typename DerivedV::Index Index;
|
||||
const size_t INVALID = std::numeric_limits<size_t>::max();
|
||||
|
||||
Index v1,v2;
|
||||
Eigen::Matrix<Index,Eigen::Dynamic,1> incident_faces;
|
||||
outer_edge(V, F, I, v1, v2, incident_faces);
|
||||
assert(incident_faces.size() > 0);
|
||||
|
||||
auto generic_fabs = [&](const Scalar& val) -> const Scalar {
|
||||
if (val >= 0) return val;
|
||||
else return -val;
|
||||
};
|
||||
|
||||
Scalar max_nx = 0;
|
||||
size_t outer_fid = INVALID;
|
||||
const size_t num_incident_faces = incident_faces.size();
|
||||
for (size_t i=0; i<num_incident_faces; i++)
|
||||
{
|
||||
const auto& fid = incident_faces(i);
|
||||
const Scalar nx = N(fid, 0);
|
||||
if (outer_fid == INVALID) {
|
||||
max_nx = nx;
|
||||
outer_fid = fid;
|
||||
} else {
|
||||
if (generic_fabs(nx) > generic_fabs(max_nx)) {
|
||||
max_nx = nx;
|
||||
outer_fid = fid;
|
||||
} else if (nx == -max_nx && nx > 0) {
|
||||
max_nx = nx;
|
||||
outer_fid = fid;
|
||||
} else if (nx == max_nx) {
|
||||
if ((max_nx >= 0 && outer_fid < fid) ||
|
||||
(max_nx < 0 && outer_fid > fid)) {
|
||||
max_nx = nx;
|
||||
outer_fid = fid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(outer_fid != INVALID);
|
||||
f = outer_fid;
|
||||
flipped = max_nx < 0;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned long>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, unsigned long&, bool&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int&, bool&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned long>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, unsigned long&, bool&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int&, bool&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned long>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, unsigned long&, bool&);
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, int&, bool&);
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 1, -1, -1>, unsigned long>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 1, -1, -1> > const&, unsigned long&, bool&);
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int&, bool&);
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int&, bool&);
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, int&, bool&);
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, int&, bool&);
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int&, bool&);
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned long>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, unsigned long&, bool&);
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int&, bool&);
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, int&, bool&);
|
||||
template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int&, bool&);
|
||||
#ifdef WIN32
|
||||
template void igl::copyleft::cgal::outer_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned __int64>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, unsigned __int64 &, bool &);
|
||||
template void igl::copyleft::cgal::outer_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned __int64>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, unsigned __int64 &, bool &);
|
||||
template void igl::copyleft::cgal::outer_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned __int64>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, unsigned __int64 &, bool &);
|
||||
#endif
|
||||
#endif
|
||||
91
src/libigl/igl/copyleft/cgal/outer_facet.h
Normal file
91
src/libigl/igl/copyleft/cgal/outer_facet.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef IGL_COPYLEFT_CGAL_OUTER_FACET_H
|
||||
#define IGL_COPYLEFT_CGAL_OUTER_FACET_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Find a facet that is reachable from infinity without crossing any faces.
|
||||
// Such facet is called "outer facet."
|
||||
//
|
||||
// Precondition: The input mesh must have all self-intersection resolved. I.e
|
||||
// there is no duplicated vertices, no overlapping edge and no intersecting
|
||||
// faces (the only exception is there could be topologically duplicated faces).
|
||||
// See cgal::remesh_self_intersections.h for how to obtain such input.
|
||||
//
|
||||
// This function differ from igl::outer_facet() in the fact this
|
||||
// function is more robust because it does not rely on facet normals.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices into V
|
||||
// I #I list of facets to consider
|
||||
// Outputs:
|
||||
// f Index of the outer facet.
|
||||
// flipped true iff the normal of f points inwards.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename IndexType
|
||||
>
|
||||
IGL_INLINE void outer_facet(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
const Eigen::PlainObjectBase<DerivedI> & I,
|
||||
IndexType & f,
|
||||
bool & flipped);
|
||||
|
||||
// Find a facet that is reachable from infinity without crossing any faces.
|
||||
// Such facet is called "outer facet."
|
||||
//
|
||||
// Precondition: The input mesh must have all self-intersection resolved.
|
||||
// I.e there is no duplicated vertices, no overlapping edge and no
|
||||
// intersecting faces (the only exception is there could be topologically
|
||||
// duplicated faces). See cgal::remesh_self_intersections.h for how to
|
||||
// obtain such input.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices into V
|
||||
// N #N by 3 list of face normals
|
||||
// I #I list of facets to consider
|
||||
// Outputs:
|
||||
// f Index of the outer facet.
|
||||
// flipped true iff the normal of f points inwards.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedN,
|
||||
typename DerivedI,
|
||||
typename IndexType
|
||||
>
|
||||
IGL_INLINE void outer_facet(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
const Eigen::PlainObjectBase<DerivedN> & N,
|
||||
const Eigen::PlainObjectBase<DerivedI> & I,
|
||||
IndexType & f,
|
||||
bool & flipped);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "outer_facet.cpp"
|
||||
#endif
|
||||
#endif
|
||||
535
src/libigl/igl/copyleft/cgal/outer_hull.cpp
Normal file
535
src/libigl/igl/copyleft/cgal/outer_hull.cpp
Normal file
|
|
@ -0,0 +1,535 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "outer_hull.h"
|
||||
#include "extract_cells.h"
|
||||
#include "remesh_self_intersections.h"
|
||||
#include "assign.h"
|
||||
#include "../../remove_unreferenced.h"
|
||||
|
||||
#include <CGAL/AABB_tree.h>
|
||||
#include <CGAL/AABB_traits.h>
|
||||
#include <CGAL/AABB_triangle_primitive.h>
|
||||
#include <CGAL/intersections.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedHV,
|
||||
typename DerivedHF,
|
||||
typename DerivedJ,
|
||||
typename Derivedflip>
|
||||
IGL_INLINE void igl::copyleft::cgal::outer_hull(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedHV> & HV,
|
||||
Eigen::PlainObjectBase<DerivedHF> & HF,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J,
|
||||
Eigen::PlainObjectBase<Derivedflip> & flip)
|
||||
{
|
||||
// Exact types
|
||||
typedef CGAL::Epeck Kernel;
|
||||
typedef Kernel::FT ExactScalar;
|
||||
typedef
|
||||
Eigen::Matrix<
|
||||
ExactScalar,
|
||||
Eigen::Dynamic,
|
||||
Eigen::Dynamic,
|
||||
DerivedHV::IsRowMajor>
|
||||
MatrixXES;
|
||||
// Remesh self-intersections
|
||||
MatrixXES Vr;
|
||||
DerivedHF Fr;
|
||||
DerivedJ Jr;
|
||||
{
|
||||
RemeshSelfIntersectionsParam params;
|
||||
params.stitch_all = true;
|
||||
Eigen::VectorXi I;
|
||||
Eigen::MatrixXi IF;
|
||||
remesh_self_intersections(V, F, params, Vr, Fr, IF, Jr, I);
|
||||
// Merge coinciding vertices into non-manifold vertices.
|
||||
std::for_each(Fr.data(), Fr.data()+Fr.size(),
|
||||
[&I](typename DerivedHF::Scalar& a) { a=I[a]; });
|
||||
// Remove unreferenced vertices.
|
||||
Eigen::VectorXi UIM;
|
||||
remove_unreferenced(MatrixXES(Vr),DerivedHF(Fr), Vr, Fr, UIM);
|
||||
}
|
||||
// Extract cells for each face
|
||||
Eigen::MatrixXi C;
|
||||
extract_cells(Vr,Fr,C);
|
||||
// Extract faces on ambient cell
|
||||
int num_outer = 0;
|
||||
for(int i = 0;i<C.rows();i++)
|
||||
{
|
||||
num_outer += ( C(i,0) == 0 || C(i,1) == 0 ) ? 1 : 0;
|
||||
}
|
||||
HF.resize(num_outer,3);
|
||||
J.resize(num_outer,1);
|
||||
flip.resize(num_outer,1);
|
||||
{
|
||||
int h = 0;
|
||||
for(int i = 0;i<C.rows();i++)
|
||||
{
|
||||
if(C(i,0)==0)
|
||||
{
|
||||
HF.row(h) = Fr.row(i);
|
||||
J(h) = Jr(i);
|
||||
flip(h) = false;
|
||||
h++;
|
||||
}else if(C(i,1) == 0)
|
||||
{
|
||||
HF.row(h) = Fr.row(i).reverse();
|
||||
J(h) = Jr(i);
|
||||
flip(h) = true;
|
||||
h++;
|
||||
}
|
||||
}
|
||||
assert(h == num_outer);
|
||||
}
|
||||
// Remove unreferenced vertices and re-index faces
|
||||
{
|
||||
// Cast to output type
|
||||
DerivedHV Vr_cast;
|
||||
assign(Vr,Vr_cast);
|
||||
Eigen::VectorXi I;
|
||||
remove_unreferenced(Vr_cast,DerivedHF(HF),HV,HF,I);
|
||||
}
|
||||
}
|
||||
|
||||
#include "points_inside_component.h"
|
||||
#include "order_facets_around_edges.h"
|
||||
#include "outer_facet.h"
|
||||
#include "../../sortrows.h"
|
||||
#include "../../facet_components.h"
|
||||
#include "../../winding_number.h"
|
||||
#include "../../triangle_triangle_adjacency.h"
|
||||
#include "../../unique_edge_map.h"
|
||||
#include "../../barycenter.h"
|
||||
#include "../../per_face_normals.h"
|
||||
#include "../../sort_angles.h"
|
||||
#include <Eigen/Geometry>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <iostream>
|
||||
#include <type_traits>
|
||||
#include <CGAL/number_utils.h>
|
||||
//#define IGL_OUTER_HULL_DEBUG
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedG,
|
||||
typename DerivedJ,
|
||||
typename Derivedflip>
|
||||
IGL_INLINE void igl::copyleft::cgal::outer_hull_legacy(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedG> & G,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J,
|
||||
Eigen::PlainObjectBase<Derivedflip> & flip)
|
||||
{
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
std::cerr << "Extracting outer hull" << std::endl;
|
||||
#endif
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
typedef typename DerivedF::Index Index;
|
||||
Matrix<Index,DerivedF::RowsAtCompileTime,1> C;
|
||||
typedef Matrix<typename DerivedV::Scalar,Dynamic,DerivedV::ColsAtCompileTime> MatrixXV;
|
||||
//typedef Matrix<typename DerivedF::Scalar,Dynamic,DerivedF::ColsAtCompileTime> MatrixXF;
|
||||
typedef Matrix<typename DerivedG::Scalar,Dynamic,DerivedG::ColsAtCompileTime> MatrixXG;
|
||||
typedef Matrix<typename DerivedJ::Scalar,Dynamic,DerivedJ::ColsAtCompileTime> MatrixXJ;
|
||||
const Index m = F.rows();
|
||||
|
||||
// UNUSED:
|
||||
//const auto & duplicate_simplex = [&F](const int f, const int g)->bool
|
||||
//{
|
||||
// return
|
||||
// (F(f,0) == F(g,0) && F(f,1) == F(g,1) && F(f,2) == F(g,2)) ||
|
||||
// (F(f,1) == F(g,0) && F(f,2) == F(g,1) && F(f,0) == F(g,2)) ||
|
||||
// (F(f,2) == F(g,0) && F(f,0) == F(g,1) && F(f,1) == F(g,2)) ||
|
||||
// (F(f,0) == F(g,2) && F(f,1) == F(g,1) && F(f,2) == F(g,0)) ||
|
||||
// (F(f,1) == F(g,2) && F(f,2) == F(g,1) && F(f,0) == F(g,0)) ||
|
||||
// (F(f,2) == F(g,2) && F(f,0) == F(g,1) && F(f,1) == F(g,0));
|
||||
//};
|
||||
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
cout<<"outer hull..."<<endl;
|
||||
#endif
|
||||
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
cout<<"edge map..."<<endl;
|
||||
#endif
|
||||
typedef Matrix<typename DerivedF::Scalar,Dynamic,2> MatrixX2I;
|
||||
typedef Matrix<typename DerivedF::Index,Dynamic,1> VectorXI;
|
||||
//typedef Matrix<typename DerivedV::Scalar, 3, 1> Vector3F;
|
||||
MatrixX2I E,uE;
|
||||
VectorXI EMAP;
|
||||
vector<vector<typename DerivedF::Index> > uE2E;
|
||||
unique_edge_map(F,E,uE,EMAP,uE2E);
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
for (size_t ui=0; ui<uE.rows(); ui++) {
|
||||
std::cout << ui << ": " << uE2E[ui].size() << " -- (";
|
||||
for (size_t i=0; i<uE2E[ui].size(); i++) {
|
||||
std::cout << uE2E[ui][i] << ", ";
|
||||
}
|
||||
std::cout << ")" << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::vector<std::vector<typename DerivedF::Index> > uE2oE;
|
||||
std::vector<std::vector<bool> > uE2C;
|
||||
order_facets_around_edges(V, F, uE, uE2E, uE2oE, uE2C);
|
||||
uE2E = uE2oE;
|
||||
VectorXI diIM(3*m);
|
||||
for (auto ue : uE2E) {
|
||||
for (size_t i=0; i<ue.size(); i++) {
|
||||
auto fe = ue[i];
|
||||
diIM[fe] = i;
|
||||
}
|
||||
}
|
||||
|
||||
vector<vector<vector<Index > > > TT,_1;
|
||||
triangle_triangle_adjacency(E,EMAP,uE2E,false,TT,_1);
|
||||
VectorXI counts;
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
cout<<"facet components..."<<endl;
|
||||
#endif
|
||||
facet_components(TT,C,counts);
|
||||
assert(C.maxCoeff()+1 == counts.rows());
|
||||
const size_t ncc = counts.rows();
|
||||
G.resize(0,F.cols());
|
||||
J.resize(0,1);
|
||||
flip.setConstant(m,1,false);
|
||||
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
cout<<"reindex..."<<endl;
|
||||
#endif
|
||||
// H contains list of faces on outer hull;
|
||||
vector<bool> FH(m,false);
|
||||
vector<bool> EH(3*m,false);
|
||||
vector<MatrixXG> vG(ncc);
|
||||
vector<MatrixXJ> vJ(ncc);
|
||||
vector<MatrixXJ> vIM(ncc);
|
||||
//size_t face_count = 0;
|
||||
for(size_t id = 0;id<ncc;id++)
|
||||
{
|
||||
vIM[id].resize(counts[id],1);
|
||||
}
|
||||
// current index into each IM
|
||||
vector<size_t> g(ncc,0);
|
||||
// place order of each face in its respective component
|
||||
for(Index f = 0;f<m;f++)
|
||||
{
|
||||
vIM[C(f)](g[C(f)]++) = f;
|
||||
}
|
||||
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
cout<<"barycenters..."<<endl;
|
||||
#endif
|
||||
// assumes that "resolve" has handled any coplanar cases correctly and nearly
|
||||
// coplanar cases can be sorted based on barycenter.
|
||||
MatrixXV BC;
|
||||
barycenter(V,F,BC);
|
||||
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
cout<<"loop over CCs (="<<ncc<<")..."<<endl;
|
||||
#endif
|
||||
for(Index id = 0;id<(Index)ncc;id++)
|
||||
{
|
||||
auto & IM = vIM[id];
|
||||
// starting face that's guaranteed to be on the outer hull and in this
|
||||
// component
|
||||
int f;
|
||||
bool f_flip;
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
cout<<"outer facet..."<<endl;
|
||||
#endif
|
||||
igl::copyleft::cgal::outer_facet(V,F,IM,f,f_flip);
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
cout<<"outer facet: "<<f<<endl;
|
||||
//cout << V.row(F(f, 0)) << std::endl;
|
||||
//cout << V.row(F(f, 1)) << std::endl;
|
||||
//cout << V.row(F(f, 2)) << std::endl;
|
||||
#endif
|
||||
int FHcount = 1;
|
||||
FH[f] = true;
|
||||
// Q contains list of face edges to continue traversing upong
|
||||
queue<int> Q;
|
||||
Q.push(f+0*m);
|
||||
Q.push(f+1*m);
|
||||
Q.push(f+2*m);
|
||||
flip(f) = f_flip;
|
||||
//std::cout << "face " << face_count++ << ": " << f << std::endl;
|
||||
//std::cout << "f " << F.row(f).array()+1 << std::endl;
|
||||
//cout<<"flip("<<f<<") = "<<(flip(f)?"true":"false")<<endl;
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
cout<<"BFS..."<<endl;
|
||||
#endif
|
||||
while(!Q.empty())
|
||||
{
|
||||
// face-edge
|
||||
const int e = Q.front();
|
||||
Q.pop();
|
||||
// face
|
||||
const int f = e%m;
|
||||
// corner
|
||||
const int c = e/m;
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
std::cout << "edge: " << e << ", ue: " << EMAP(e) << std::endl;
|
||||
std::cout << "face: " << f << std::endl;
|
||||
std::cout << "corner: " << c << std::endl;
|
||||
std::cout << "consistent: " << uE2C[EMAP(e)][diIM[e]] << std::endl;
|
||||
#endif
|
||||
// Should never see edge again...
|
||||
if(EH[e] == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
EH[e] = true;
|
||||
// source of edge according to f
|
||||
const int fs = flip(f)?F(f,(c+2)%3):F(f,(c+1)%3);
|
||||
// destination of edge according to f
|
||||
const int fd = flip(f)?F(f,(c+1)%3):F(f,(c+2)%3);
|
||||
// edge valence
|
||||
const size_t val = uE2E[EMAP(e)].size();
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
//std::cout << "vd: " << V.row(fd) << std::endl;
|
||||
//std::cout << "vs: " << V.row(fs) << std::endl;
|
||||
//std::cout << "edge: " << V.row(fd) - V.row(fs) << std::endl;
|
||||
for (size_t i=0; i<val; i++) {
|
||||
if (i == diIM(e)) {
|
||||
std::cout << "* ";
|
||||
} else {
|
||||
std::cout << " ";
|
||||
}
|
||||
std::cout << i << ": "
|
||||
<< " (e: " << uE2E[EMAP(e)][i] << ", f: "
|
||||
<< uE2E[EMAP(e)][i] % m * (uE2C[EMAP(e)][i] ? 1:-1) << ")" << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
// is edge consistent with edge of face used for sorting
|
||||
const int e_cons = (uE2C[EMAP(e)][diIM(e)] ? 1: -1);
|
||||
int nfei = -1;
|
||||
// Loop once around trying to find suitable next face
|
||||
for(size_t step = 1; step<val+2;step++)
|
||||
{
|
||||
const int nfei_new = (diIM(e) + 2*val + e_cons*step*(flip(f)?-1:1))%val;
|
||||
const int nf = uE2E[EMAP(e)][nfei_new] % m;
|
||||
{
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
//cout<<"Next facet: "<<(f+1)<<" --> "<<(nf+1)<<", |"<<
|
||||
// di[EMAP(e)][diIM(e)]<<" - "<<di[EMAP(e)][nfei_new]<<"| = "<<
|
||||
// abs(di[EMAP(e)][diIM(e)] - di[EMAP(e)][nfei_new])
|
||||
// <<endl;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Only use this face if not already seen
|
||||
if(!FH[nf])
|
||||
{
|
||||
nfei = nfei_new;
|
||||
//} else {
|
||||
// std::cout << "skipping face " << nfei_new << " because it is seen before"
|
||||
// << std::endl;
|
||||
}
|
||||
break;
|
||||
//} else {
|
||||
// std::cout << di[EMAP(e)][diIM(e)].transpose() << std::endl;
|
||||
// std::cout << di[EMAP(e)][diIM(nfei_new)].transpose() << std::endl;
|
||||
// std::cout << "skipping face " << nfei_new << " with identical dihedral angle"
|
||||
// << std::endl;
|
||||
}
|
||||
//#ifdef IGL_OUTER_HULL_DEBUG
|
||||
// cout<<"Skipping co-planar facet: "<<(f+1)<<" --> "<<(nf+1)<<endl;
|
||||
//#endif
|
||||
}
|
||||
|
||||
int max_ne = -1;
|
||||
if(nfei >= 0)
|
||||
{
|
||||
max_ne = uE2E[EMAP(e)][nfei];
|
||||
}
|
||||
|
||||
if(max_ne>=0)
|
||||
{
|
||||
// face of neighbor
|
||||
const int nf = max_ne%m;
|
||||
#ifdef IGL_OUTER_HULL_DEBUG
|
||||
if(!FH[nf])
|
||||
{
|
||||
// first time seeing face
|
||||
cout<<(f+1)<<" --> "<<(nf+1)<<endl;
|
||||
}
|
||||
#endif
|
||||
FH[nf] = true;
|
||||
//std::cout << "face " << face_count++ << ": " << nf << std::endl;
|
||||
//std::cout << "f " << F.row(nf).array()+1 << std::endl;
|
||||
FHcount++;
|
||||
// corner of neighbor
|
||||
const int nc = max_ne/m;
|
||||
const int nd = F(nf,(nc+2)%3);
|
||||
const bool cons = (flip(f)?fd:fs) == nd;
|
||||
flip(nf) = (cons ? flip(f) : !flip(f));
|
||||
//cout<<"flip("<<nf<<") = "<<(flip(nf)?"true":"false")<<endl;
|
||||
const int ne1 = nf+((nc+1)%3)*m;
|
||||
const int ne2 = nf+((nc+2)%3)*m;
|
||||
if(!EH[ne1])
|
||||
{
|
||||
Q.push(ne1);
|
||||
}
|
||||
if(!EH[ne2])
|
||||
{
|
||||
Q.push(ne2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
vG[id].resize(FHcount,3);
|
||||
vJ[id].resize(FHcount,1);
|
||||
//nG += FHcount;
|
||||
size_t h = 0;
|
||||
assert(counts(id) == IM.rows());
|
||||
for(int i = 0;i<counts(id);i++)
|
||||
{
|
||||
const size_t f = IM(i);
|
||||
//if(f_flip)
|
||||
//{
|
||||
// flip(f) = !flip(f);
|
||||
//}
|
||||
if(FH[f])
|
||||
{
|
||||
vG[id].row(h) = (flip(f)?F.row(f).reverse().eval():F.row(f));
|
||||
vJ[id](h,0) = f;
|
||||
h++;
|
||||
}
|
||||
}
|
||||
assert((int)h == FHcount);
|
||||
}
|
||||
}
|
||||
|
||||
// Is A inside B? Assuming A and B are consistently oriented but closed and
|
||||
// non-intersecting.
|
||||
const auto & has_overlapping_bbox = [](
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const MatrixXG & A,
|
||||
const MatrixXG & B)->bool
|
||||
{
|
||||
const auto & bounding_box = [](
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const MatrixXG & F)->
|
||||
DerivedV
|
||||
{
|
||||
DerivedV BB(2,3);
|
||||
BB<<
|
||||
1e26,1e26,1e26,
|
||||
-1e26,-1e26,-1e26;
|
||||
const size_t m = F.rows();
|
||||
for(size_t f = 0;f<m;f++)
|
||||
{
|
||||
for(size_t c = 0;c<3;c++)
|
||||
{
|
||||
const auto & vfc = V.row(F(f,c)).eval();
|
||||
BB(0,0) = std::min(BB(0,0), vfc(0,0));
|
||||
BB(0,1) = std::min(BB(0,1), vfc(0,1));
|
||||
BB(0,2) = std::min(BB(0,2), vfc(0,2));
|
||||
BB(1,0) = std::max(BB(1,0), vfc(0,0));
|
||||
BB(1,1) = std::max(BB(1,1), vfc(0,1));
|
||||
BB(1,2) = std::max(BB(1,2), vfc(0,2));
|
||||
}
|
||||
}
|
||||
return BB;
|
||||
};
|
||||
// A lot of the time we're dealing with unrelated, distant components: cull
|
||||
// them.
|
||||
DerivedV ABB = bounding_box(V,A);
|
||||
DerivedV BBB = bounding_box(V,B);
|
||||
if( (BBB.row(0)-ABB.row(1)).maxCoeff()>0 ||
|
||||
(ABB.row(0)-BBB.row(1)).maxCoeff()>0 )
|
||||
{
|
||||
// bounding boxes do not overlap
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Reject components which are completely inside other components
|
||||
vector<bool> keep(ncc,true);
|
||||
size_t nG = 0;
|
||||
// This is O( ncc * ncc * m)
|
||||
for(size_t id = 0;id<ncc;id++)
|
||||
{
|
||||
if (!keep[id]) continue;
|
||||
std::vector<size_t> unresolved;
|
||||
for(size_t oid = 0;oid<ncc;oid++)
|
||||
{
|
||||
if(id == oid || !keep[oid])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (has_overlapping_bbox(V, vG[id], vG[oid])) {
|
||||
unresolved.push_back(oid);
|
||||
}
|
||||
}
|
||||
const size_t num_unresolved_components = unresolved.size();
|
||||
DerivedV query_points(num_unresolved_components, 3);
|
||||
for (size_t i=0; i<num_unresolved_components; i++) {
|
||||
const size_t oid = unresolved[i];
|
||||
DerivedF f = vG[oid].row(0);
|
||||
query_points(i,0) = (V(f(0,0), 0) + V(f(0,1), 0) + V(f(0,2), 0))/3.0;
|
||||
query_points(i,1) = (V(f(0,0), 1) + V(f(0,1), 1) + V(f(0,2), 1))/3.0;
|
||||
query_points(i,2) = (V(f(0,0), 2) + V(f(0,1), 2) + V(f(0,2), 2))/3.0;
|
||||
}
|
||||
Eigen::VectorXi inside;
|
||||
igl::copyleft::cgal::points_inside_component(V, vG[id], query_points, inside);
|
||||
assert((size_t)inside.size() == num_unresolved_components);
|
||||
for (size_t i=0; i<num_unresolved_components; i++) {
|
||||
if (inside(i, 0)) {
|
||||
const size_t oid = unresolved[i];
|
||||
keep[oid] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (size_t id = 0; id<ncc; id++) {
|
||||
if (keep[id]) {
|
||||
nG += vJ[id].rows();
|
||||
}
|
||||
}
|
||||
|
||||
// collect G and J across components
|
||||
G.resize(nG,3);
|
||||
J.resize(nG,1);
|
||||
{
|
||||
size_t off = 0;
|
||||
for(Index id = 0;id<(Index)ncc;id++)
|
||||
{
|
||||
if(keep[id])
|
||||
{
|
||||
assert(vG[id].rows() == vJ[id].rows());
|
||||
G.block(off,0,vG[id].rows(),vG[id].cols()) = vG[id];
|
||||
J.block(off,0,vJ[id].rows(),vJ[id].cols()) = vJ[id];
|
||||
off += vG[id].rows();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::copyleft::cgal::outer_hull<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::outer_hull_legacy< Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > &, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > &, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > &);
|
||||
template void igl::copyleft::cgal::outer_hull_legacy< Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::outer_hull_legacy<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::outer_hull_legacy<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
84
src/libigl/igl/copyleft/cgal/outer_hull.h
Normal file
84
src/libigl/igl/copyleft/cgal/outer_hull.h
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_OUTER_HULL_H
|
||||
#define IGL_COPYLEFT_CGAL_OUTER_HULL_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Compute the "outer hull" of a piecewise constant winding number induce
|
||||
// triangle mesh (V,F).
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices into V
|
||||
// Outputs:
|
||||
// HV #HV by 3 list of output vertex positions
|
||||
// HF #HF by 3 list of output triangle indices into HV
|
||||
// J #HF list of indices into F
|
||||
// flip #HF list of whether facet was flipped when added to HF
|
||||
//
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedHV,
|
||||
typename DerivedHF,
|
||||
typename DerivedJ,
|
||||
typename Derivedflip>
|
||||
IGL_INLINE void outer_hull(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedHV> & HV,
|
||||
Eigen::PlainObjectBase<DerivedHF> & HF,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J,
|
||||
Eigen::PlainObjectBase<Derivedflip> & flip);
|
||||
// Compute the "outer hull" of a potentially non-manifold mesh (V,F) whose
|
||||
// intersections have been "resolved" (e.g. using `cork` or
|
||||
// `igl::copyleft::cgal::selfintersect`). The outer hull is defined to be all facets
|
||||
// (regardless of orientation) for which there exists some path from infinity
|
||||
// to the face without intersecting any other facets. For solids, this is the
|
||||
// surface of the solid. In general this includes any thin "wings" or
|
||||
// "flaps". This implementation largely follows Section 3.6 of "Direct
|
||||
// repair of self-intersecting meshes" [Attene 2014].
|
||||
//
|
||||
// Note: This doesn't require the input mesh to be piecewise constant
|
||||
// winding number, but won't handle multiple non-nested connected
|
||||
// components.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices into V
|
||||
// Outputs:
|
||||
// G #G by 3 list of output triangle indices into V
|
||||
// J #G list of indices into F
|
||||
// flip #F list of whether facet was added to G **and** flipped orientation
|
||||
// (false for faces not added to G)
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedG,
|
||||
typename DerivedJ,
|
||||
typename Derivedflip>
|
||||
IGL_INLINE void outer_hull_legacy(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedG> & G,
|
||||
Eigen::PlainObjectBase<DerivedJ> & J,
|
||||
Eigen::PlainObjectBase<Derivedflip> & flip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "outer_hull.cpp"
|
||||
#endif
|
||||
#endif
|
||||
124
src/libigl/igl/copyleft/cgal/peel_outer_hull_layers.cpp
Normal file
124
src/libigl/igl/copyleft/cgal/peel_outer_hull_layers.cpp
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "peel_outer_hull_layers.h"
|
||||
#include "outer_hull.h"
|
||||
#include "../../LinSpaced.h"
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
//#define IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
|
||||
#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
|
||||
#include "../../writePLY.h"
|
||||
#include "../../writeDMAT.h"
|
||||
#include "../../STR.h"
|
||||
#endif
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename Derivedflip>
|
||||
IGL_INLINE size_t igl::copyleft::cgal::peel_outer_hull_layers(
|
||||
const Eigen::PlainObjectBase<DerivedV > & V,
|
||||
const Eigen::PlainObjectBase<DerivedF > & F,
|
||||
Eigen::PlainObjectBase<DerivedI> & I,
|
||||
Eigen::PlainObjectBase<Derivedflip > & flip)
|
||||
{
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
typedef typename DerivedF::Index Index;
|
||||
typedef Matrix<typename DerivedF::Scalar,Dynamic,DerivedF::ColsAtCompileTime> MatrixXF;
|
||||
typedef Matrix<Index,Dynamic,1> MatrixXI;
|
||||
typedef Matrix<typename Derivedflip::Scalar,Dynamic,Derivedflip::ColsAtCompileTime> MatrixXflip;
|
||||
const Index m = F.rows();
|
||||
#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
|
||||
cout<<"peel outer hull layers..."<<endl;
|
||||
#endif
|
||||
#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
|
||||
cout<<"calling outer hull..."<<endl;
|
||||
writePLY(STR("peel-outer-hull-input.ply"),V,F);
|
||||
#endif
|
||||
|
||||
#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
|
||||
cout<<"resize output ..."<<endl;
|
||||
#endif
|
||||
// keep track of iteration parity and whether flipped in hull
|
||||
MatrixXF Fr = F;
|
||||
I.resize(m,1);
|
||||
flip.resize(m,1);
|
||||
// Keep track of index map
|
||||
MatrixXI IM = igl::LinSpaced<MatrixXI >(m,0,m-1);
|
||||
// This is O(n * layers)
|
||||
MatrixXI P(m,1);
|
||||
Index iter = 0;
|
||||
while(Fr.size() > 0)
|
||||
{
|
||||
assert(Fr.rows() == IM.rows());
|
||||
// Compute outer hull of current Fr
|
||||
MatrixXF Fo;
|
||||
MatrixXI Jo;
|
||||
MatrixXflip flipr;
|
||||
#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
|
||||
{
|
||||
cout<<"calling outer hull..." << iter <<endl;
|
||||
std::stringstream ss;
|
||||
ss << "outer_hull_" << iter << ".ply";
|
||||
Eigen::MatrixXd vertices(V.rows(), V.cols());
|
||||
std::transform(V.data(), V.data() + V.rows()*V.cols(),
|
||||
vertices.data(),
|
||||
[](typename DerivedV::Scalar val)
|
||||
{return CGAL::to_double(val); });
|
||||
writePLY(ss.str(), vertices, Fr);
|
||||
}
|
||||
#endif
|
||||
outer_hull_legacy(V,Fr,Fo,Jo,flipr);
|
||||
#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
|
||||
writePLY(STR("outer-hull-output-"<<iter<<".ply"),V,Fo);
|
||||
cout<<"reindex, flip..."<<endl;
|
||||
#endif
|
||||
assert(Fo.rows() != 0);
|
||||
assert(Fo.rows() == Jo.rows());
|
||||
// all faces in Fo of Fr
|
||||
vector<bool> in_outer(Fr.rows(),false);
|
||||
for(Index g = 0;g<Jo.rows();g++)
|
||||
{
|
||||
I(IM(Jo(g))) = iter;
|
||||
P(IM(Jo(g))) = iter;
|
||||
in_outer[Jo(g)] = true;
|
||||
flip(IM(Jo(g))) = flipr(Jo(g));
|
||||
}
|
||||
// Fr = Fr - Fo
|
||||
// update IM
|
||||
MatrixXF prev_Fr = Fr;
|
||||
MatrixXI prev_IM = IM;
|
||||
Fr.resize(prev_Fr.rows() - Fo.rows(),F.cols());
|
||||
IM.resize(Fr.rows());
|
||||
{
|
||||
Index g = 0;
|
||||
for(Index f = 0;f<prev_Fr.rows();f++)
|
||||
{
|
||||
if(!in_outer[f])
|
||||
{
|
||||
Fr.row(g) = prev_Fr.row(f);
|
||||
IM(g) = prev_IM(f);
|
||||
g++;
|
||||
}
|
||||
}
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
return iter;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
template unsigned long igl::copyleft::cgal::peel_outer_hull_layers<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template size_t igl::copyleft::cgal::peel_outer_hull_layers<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
47
src/libigl/igl/copyleft/cgal/peel_outer_hull_layers.h
Normal file
47
src/libigl/igl/copyleft/cgal/peel_outer_hull_layers.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_PEEL_OUTER_HULL_LAYERS_H
|
||||
#define IGL_COPYLEFT_CGAL_PEEL_OUTER_HULL_LAYERS_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Computes necessary generic information for boolean operations by
|
||||
// successively "peeling" off the "outer hull" of a mesh (V,F) resulting from
|
||||
// "resolving" all (self-)intersections.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices into V
|
||||
// Outputs:
|
||||
// I #F list of which peel Iation a facet belongs
|
||||
// flip #F list of whether a facet's orientation was flipped when facet
|
||||
// "peeled" into its associated outer hull layer.
|
||||
// Returns number of peels
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename Derivedflip>
|
||||
IGL_INLINE size_t peel_outer_hull_layers(
|
||||
const Eigen::PlainObjectBase<DerivedV > & V,
|
||||
const Eigen::PlainObjectBase<DerivedF > & F,
|
||||
Eigen::PlainObjectBase<DerivedI > & I,
|
||||
Eigen::PlainObjectBase<Derivedflip > & flip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "peel_outer_hull_layers.cpp"
|
||||
#endif
|
||||
#endif
|
||||
33
src/libigl/igl/copyleft/cgal/peel_winding_number_layers.cpp
Normal file
33
src/libigl/igl/copyleft/cgal/peel_winding_number_layers.cpp
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#include "peel_winding_number_layers.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "propagate_winding_numbers.h"
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedW >
|
||||
IGL_INLINE size_t igl::copyleft::cgal::peel_winding_number_layers(
|
||||
const Eigen::PlainObjectBase<DerivedV > & V,
|
||||
const Eigen::PlainObjectBase<DerivedF > & F,
|
||||
Eigen::PlainObjectBase<DerivedW>& W) {
|
||||
const size_t num_faces = F.rows();
|
||||
Eigen::VectorXi labels(num_faces);
|
||||
labels.setZero();
|
||||
|
||||
Eigen::MatrixXi winding_numbers;
|
||||
igl::copyleft::cgal::propagate_winding_numbers(V, F, labels, winding_numbers);
|
||||
assert(winding_numbers.rows() == num_faces);
|
||||
assert(winding_numbers.cols() == 2);
|
||||
|
||||
int min_w = winding_numbers.minCoeff();
|
||||
int max_w = winding_numbers.maxCoeff();
|
||||
assert(max_w > min_w);
|
||||
|
||||
W.resize(num_faces, 1);
|
||||
for (size_t i=0; i<num_faces; i++) {
|
||||
W(i, 0) = winding_numbers(i, 1);
|
||||
}
|
||||
return max_w - min_w;
|
||||
}
|
||||
24
src/libigl/igl/copyleft/cgal/peel_winding_number_layers.h
Normal file
24
src/libigl/igl/copyleft/cgal/peel_winding_number_layers.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef IGL_COPYLEFT_CGAL_PEEL_WINDING_NUMBER_LAYERS_H
|
||||
#define IGL_COPYLEFT_CGAL_PEEL_WINDING_NUMBER_LAYERS_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl {
|
||||
namespace copyleft {
|
||||
namespace cgal {
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedW >
|
||||
IGL_INLINE size_t peel_winding_number_layers(
|
||||
const Eigen::PlainObjectBase<DerivedV > & V,
|
||||
const Eigen::PlainObjectBase<DerivedF > & F,
|
||||
Eigen::PlainObjectBase<DerivedW>& W);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "peel_winding_number_layers.cpp"
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_PIECEWISE_CONSTANT_WINDING_NUMBER_H
|
||||
#define IGL_COPYLEFT_CGAL_PIECEWISE_CONSTANT_WINDING_NUMBER_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// PIECEWISE_CONSTANT_WINDING_NUMBER Determine if a given mesh induces a
|
||||
// piecewise constant winding number field: Is this mesh valid input to
|
||||
// solid set operations.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of mesh vertex positions
|
||||
// F #F by 3 list of triangle indices into V
|
||||
// Returns true if the mesh _combinatorially_ induces a piecewise
|
||||
// constant winding number field.
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF>
|
||||
IGL_INLINE bool piecewise_constant_winding_number(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "piecewise_constant_winding_number.cpp"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
181
src/libigl/igl/copyleft/cgal/point_areas.cpp
Normal file
181
src/libigl/igl/copyleft/cgal/point_areas.cpp
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
#include "point_areas.h"
|
||||
#include "delaunay_triangulation.h"
|
||||
|
||||
#include "../../colon.h"
|
||||
#include "../../slice.h"
|
||||
#include "../../slice_mask.h"
|
||||
#include "../../parallel_for.h"
|
||||
|
||||
#include "CGAL/Exact_predicates_inexact_constructions_kernel.h"
|
||||
#include "CGAL/Triangulation_vertex_base_with_info_2.h"
|
||||
#include "CGAL/Triangulation_data_structure_2.h"
|
||||
#include "CGAL/Delaunay_triangulation_2.h"
|
||||
|
||||
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||
typedef CGAL::Triangulation_vertex_base_with_info_2<unsigned int, Kernel> Vb;
|
||||
typedef CGAL::Triangulation_data_structure_2<Vb> Tds;
|
||||
typedef CGAL::Delaunay_triangulation_2<Kernel, Tds> Delaunay;
|
||||
typedef Kernel::Point_2 Point;
|
||||
|
||||
namespace igl {
|
||||
namespace copyleft{
|
||||
namespace cgal{
|
||||
|
||||
template <typename DerivedP, typename DerivedI, typename DerivedN,
|
||||
typename DerivedA>
|
||||
IGL_INLINE void point_areas(
|
||||
const Eigen::MatrixBase<DerivedP>& P,
|
||||
const Eigen::MatrixBase<DerivedI>& I,
|
||||
const Eigen::MatrixBase<DerivedN>& N,
|
||||
Eigen::PlainObjectBase<DerivedA> & A)
|
||||
{
|
||||
Eigen::MatrixXd T;
|
||||
point_areas(P,I,N,A,T);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedP, typename DerivedI, typename DerivedN,
|
||||
typename DerivedA, typename DerivedT>
|
||||
IGL_INLINE void point_areas(
|
||||
const Eigen::MatrixBase<DerivedP>& P,
|
||||
const Eigen::MatrixBase<DerivedI>& I,
|
||||
const Eigen::MatrixBase<DerivedN>& N,
|
||||
Eigen::PlainObjectBase<DerivedA> & A,
|
||||
Eigen::PlainObjectBase<DerivedT> & T)
|
||||
{
|
||||
typedef typename DerivedP::Scalar real;
|
||||
typedef typename DerivedN::Scalar scalarN;
|
||||
typedef typename DerivedA::Scalar scalarA;
|
||||
typedef Eigen::Matrix<real,1,3> RowVec3;
|
||||
typedef Eigen::Matrix<real,1,2> RowVec2;
|
||||
|
||||
typedef Eigen::Matrix<real, Eigen::Dynamic, Eigen::Dynamic> MatrixP;
|
||||
typedef Eigen::Matrix<scalarN, Eigen::Dynamic, Eigen::Dynamic> MatrixN;
|
||||
typedef Eigen::Matrix<typename DerivedN::Scalar,
|
||||
Eigen::Dynamic, Eigen::Dynamic> VecotorO;
|
||||
typedef Eigen::Matrix<typename DerivedI::Scalar,
|
||||
Eigen::Dynamic, Eigen::Dynamic> MatrixI;
|
||||
|
||||
|
||||
|
||||
const int n = P.rows();
|
||||
|
||||
assert(P.cols() == 3 && "P must have exactly 3 columns");
|
||||
assert(P.rows() == N.rows()
|
||||
&& "P and N must have the same number of rows");
|
||||
assert(P.rows() == I.rows()
|
||||
&& "P and I must have the same number of rows");
|
||||
|
||||
A.setZero(n,1);
|
||||
T.setZero(n,3);
|
||||
igl::parallel_for(P.rows(),[&](int i)
|
||||
{
|
||||
MatrixI neighbor_index = I.row(i);
|
||||
MatrixP neighbors;
|
||||
igl::slice(P,neighbor_index,1,neighbors);
|
||||
if(N.rows() && neighbors.rows() > 1){
|
||||
MatrixN neighbor_normals;
|
||||
igl::slice(N,neighbor_index,1,neighbor_normals);
|
||||
Eigen::Matrix<scalarN,1,3> poi_normal = neighbor_normals.row(0);
|
||||
Eigen::Matrix<scalarN,Eigen::Dynamic,1> dotprod =
|
||||
poi_normal(0)*neighbor_normals.col(0)
|
||||
+ poi_normal(1)*neighbor_normals.col(1)
|
||||
+ poi_normal(2)*neighbor_normals.col(2);
|
||||
Eigen::Array<bool,Eigen::Dynamic,1> keep = dotprod.array() > 0;
|
||||
igl::slice_mask(Eigen::MatrixXd(neighbors),keep,1,neighbors);
|
||||
}
|
||||
if(neighbors.rows() <= 2){
|
||||
A(i) = 0;
|
||||
} else {
|
||||
//subtract the mean from neighbors, then take svd,
|
||||
//the scores will be U*S. This is our pca plane fitting
|
||||
RowVec3 mean = neighbors.colwise().mean();
|
||||
MatrixP mean_centered = neighbors.rowwise() - mean;
|
||||
Eigen::JacobiSVD<MatrixP> svd(mean_centered,
|
||||
Eigen::ComputeThinU | Eigen::ComputeThinV);
|
||||
MatrixP scores = svd.matrixU() * svd.singularValues().asDiagonal();
|
||||
|
||||
T.row(i) = svd.matrixV().col(2).transpose();
|
||||
if(T.row(i).dot(N.row(i)) < 0){
|
||||
T.row(i) *= -1;
|
||||
}
|
||||
|
||||
MatrixP plane;
|
||||
igl::slice(scores,igl::colon<int>(0,scores.rows()-1),
|
||||
igl::colon<int>(0,1),plane);
|
||||
|
||||
std::vector< std::pair<Point,unsigned> > points;
|
||||
//This is where we obtain a delaunay triangulation of the points
|
||||
for(unsigned iter = 0; iter < plane.rows(); iter++){
|
||||
points.push_back( std::make_pair(
|
||||
Point(plane(iter,0),plane(iter,1)), iter ) );
|
||||
}
|
||||
Delaunay triangulation;
|
||||
triangulation.insert(points.begin(),points.end());
|
||||
Eigen::MatrixXi F(triangulation.number_of_faces(),3);
|
||||
int f_row = 0;
|
||||
for(Delaunay::Finite_faces_iterator fit =
|
||||
triangulation.finite_faces_begin();
|
||||
fit != triangulation.finite_faces_end(); ++fit) {
|
||||
Delaunay::Face_handle face = fit;
|
||||
F.row(f_row) = Eigen::RowVector3i((int)face->vertex(0)->info(),
|
||||
(int)face->vertex(1)->info(),
|
||||
(int)face->vertex(2)->info());
|
||||
f_row++;
|
||||
}
|
||||
|
||||
//Here we calculate the voronoi area of the point
|
||||
scalarA area_accumulator = 0;
|
||||
for(int f = 0; f < F.rows(); f++){
|
||||
int X = -1;
|
||||
for(int face_iter = 0; face_iter < 3; face_iter++){
|
||||
if(F(f,face_iter) == 0){
|
||||
X = face_iter;
|
||||
}
|
||||
}
|
||||
if(X >= 0){
|
||||
//Triangle XYZ with X being the point we want the area of
|
||||
int Y = (X+1)%3;
|
||||
int Z = (X+2)%3;
|
||||
scalarA x = (plane.row(F(f,Y))-plane.row(F(f,Z))).norm();
|
||||
scalarA y = (plane.row(F(f,X))-plane.row(F(f,Z))).norm();
|
||||
scalarA z = (plane.row(F(f,Y))-plane.row(F(f,X))).norm();
|
||||
scalarA cosX = (z*z + y*y - x*x)/(2*y*z);
|
||||
scalarA cosY = (z*z + x*x - y*y)/(2*x*z);
|
||||
scalarA cosZ = (x*x + y*y - z*z)/(2*y*x);
|
||||
Eigen::Matrix<scalarA,1,3> barycentric;
|
||||
barycentric << x*cosX, y*cosY, z*cosZ;
|
||||
barycentric /= (barycentric(0)+barycentric(1)+barycentric(2));
|
||||
|
||||
//TODO: to make numerically stable, reorder so that x≥y≥z:
|
||||
scalarA full_area = 0.25*std::sqrt(
|
||||
(x+(y+z))*(z-(x-y))*(z+(x-y))*(x+(y-z)));
|
||||
Eigen::Matrix<scalarA,1,3> partial_area =
|
||||
barycentric * full_area;
|
||||
if(cosX < 0){
|
||||
area_accumulator += 0.5*full_area;
|
||||
} else if (cosY < 0 || cosZ < 0){
|
||||
area_accumulator += 0.25*full_area;
|
||||
} else {
|
||||
area_accumulator += (partial_area(1) + partial_area(2))/2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(std::isfinite(area_accumulator)){
|
||||
A(i) = area_accumulator;
|
||||
} else {
|
||||
A(i) = 0;
|
||||
}
|
||||
}
|
||||
},1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
78
src/libigl/igl/copyleft/cgal/point_areas.h
Normal file
78
src/libigl/igl/copyleft/cgal/point_areas.h
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2018 Gavin Barill <gavinpcb@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/
|
||||
|
||||
#ifndef IGL_POINT_AREAS_H
|
||||
#define IGL_POINT_AREAS_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Given a 3D set of points P, each with a list of k-nearest-neighbours,
|
||||
// estimate the geodesic voronoi area associated with each point.
|
||||
//
|
||||
// The k nearest neighbours may be known from running igl::knn_octree on
|
||||
// the output data from igl::octree. We reccomend using a k value
|
||||
// between 15 and 20 inclusive for accurate area estimation.
|
||||
//
|
||||
// N is used filter the neighbours, to ensure area estimation only occurs
|
||||
// using neighbors that are on the same side of the surface (ie for thin
|
||||
// sheets), as well as to solve the orientation ambiguity of the tangent
|
||||
// plane normal.
|
||||
//
|
||||
// Note: This function *should* be implemented by pre-filtering I, rather
|
||||
// than filtering in this function using N. In this case, the function
|
||||
// would only take P and I as input.
|
||||
//
|
||||
// Inputs:
|
||||
// P #P by 3 list of point locations
|
||||
// I #P by k list of k-nearest-neighbor indices into P
|
||||
// N #P by 3 list of point normals
|
||||
// Outputs:
|
||||
// A #P list of estimated areas
|
||||
template <typename DerivedP, typename DerivedI, typename DerivedN,
|
||||
typename DerivedA>
|
||||
IGL_INLINE void point_areas(
|
||||
const Eigen::MatrixBase<DerivedP>& P,
|
||||
const Eigen::MatrixBase<DerivedI>& I,
|
||||
const Eigen::MatrixBase<DerivedN>& N,
|
||||
Eigen::PlainObjectBase<DerivedA> & A);
|
||||
|
||||
// This version can be used to output the tangent plane normal at each
|
||||
// point. Since we area already fitting a plane to each point's neighbour
|
||||
// set, the tangent plane normals come "for free"
|
||||
//
|
||||
// Inputs:
|
||||
// P #P by 3 list of point locations
|
||||
// I #P by k list of k-nearest-neighbor indices into P
|
||||
// N #P by 3 list of point normals
|
||||
// Outputs:
|
||||
// A #P list of estimated areas
|
||||
// T #P by 3 list of tangent plane normals for each point
|
||||
template <typename DerivedP, typename DerivedI, typename DerivedN,
|
||||
typename DerivedA, typename DerivedT>
|
||||
IGL_INLINE void point_areas(
|
||||
const Eigen::MatrixBase<DerivedP>& P,
|
||||
const Eigen::MatrixBase<DerivedI>& I,
|
||||
const Eigen::MatrixBase<DerivedN>& N,
|
||||
Eigen::PlainObjectBase<DerivedA> & A,
|
||||
Eigen::PlainObjectBase<DerivedT> & T);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "point_areas.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
138
src/libigl/igl/copyleft/cgal/point_mesh_squared_distance.cpp
Normal file
138
src/libigl/igl/copyleft/cgal/point_mesh_squared_distance.cpp
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "point_mesh_squared_distance.h"
|
||||
#include "mesh_to_cgal_triangle_list.h"
|
||||
#include "assign_scalar.h"
|
||||
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedP,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedsqrD,
|
||||
typename DerivedI,
|
||||
typename DerivedC>
|
||||
IGL_INLINE void igl::copyleft::cgal::point_mesh_squared_distance(
|
||||
const Eigen::PlainObjectBase<DerivedP> & P,
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
|
||||
Eigen::PlainObjectBase<DerivedI> & I,
|
||||
Eigen::PlainObjectBase<DerivedC> & C)
|
||||
{
|
||||
using namespace std;
|
||||
typedef CGAL::Triangle_3<Kernel> Triangle_3;
|
||||
typedef typename std::vector<Triangle_3>::iterator Iterator;
|
||||
typedef CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
|
||||
typedef CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
|
||||
typedef CGAL::AABB_tree<AABB_triangle_traits> Tree;
|
||||
Tree tree;
|
||||
vector<Triangle_3> T;
|
||||
point_mesh_squared_distance_precompute(V,F,tree,T);
|
||||
return point_mesh_squared_distance(P,tree,T,sqrD,I,C);
|
||||
}
|
||||
|
||||
template <typename Kernel, typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE void igl::copyleft::cgal::point_mesh_squared_distance_precompute(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
CGAL::AABB_tree<
|
||||
CGAL::AABB_traits<Kernel,
|
||||
CGAL::AABB_triangle_primitive<Kernel,
|
||||
typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
|
||||
>
|
||||
>
|
||||
> & tree,
|
||||
std::vector<CGAL::Triangle_3<Kernel> > & T)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
typedef CGAL::Triangle_3<Kernel> Triangle_3;
|
||||
typedef CGAL::Point_3<Kernel> Point_3;
|
||||
typedef typename std::vector<Triangle_3>::iterator Iterator;
|
||||
typedef CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
|
||||
typedef CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
|
||||
typedef CGAL::AABB_tree<AABB_triangle_traits> Tree;
|
||||
|
||||
// Must be 3D
|
||||
assert(V.cols() == 3);
|
||||
// Must be triangles
|
||||
assert(F.cols() == 3);
|
||||
|
||||
// WTF ALERT!!!!
|
||||
//
|
||||
// There's a bug in clang probably or at least in cgal. Without calling this
|
||||
// line (I guess invoking some compilation from <vector>), clang will vomit
|
||||
// errors inside CGAL.
|
||||
//
|
||||
// http://stackoverflow.com/questions/27748442/is-clangs-c11-support-reliable
|
||||
T.reserve(0);
|
||||
|
||||
// Make list of cgal triangles
|
||||
mesh_to_cgal_triangle_list(V,F,T);
|
||||
tree.clear();
|
||||
tree.insert(T.begin(),T.end());
|
||||
tree.accelerate_distance_queries();
|
||||
// accelerate_distance_queries doesn't seem actually to do _all_ of the
|
||||
// precomputation. the tree (despite being const) will still do more
|
||||
// precomputation and reorganizing on the first call of `closest_point` or
|
||||
// `closest_point_and_primitive`. Therefore, call it once here.
|
||||
tree.closest_point_and_primitive(Point_3(0,0,0));
|
||||
}
|
||||
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedP,
|
||||
typename DerivedsqrD,
|
||||
typename DerivedI,
|
||||
typename DerivedC>
|
||||
IGL_INLINE void igl::copyleft::cgal::point_mesh_squared_distance(
|
||||
const Eigen::PlainObjectBase<DerivedP> & P,
|
||||
const CGAL::AABB_tree<
|
||||
CGAL::AABB_traits<Kernel,
|
||||
CGAL::AABB_triangle_primitive<Kernel,
|
||||
typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
|
||||
>
|
||||
>
|
||||
> & tree,
|
||||
const std::vector<CGAL::Triangle_3<Kernel> > & T,
|
||||
Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
|
||||
Eigen::PlainObjectBase<DerivedI> & I,
|
||||
Eigen::PlainObjectBase<DerivedC> & C)
|
||||
{
|
||||
typedef CGAL::Triangle_3<Kernel> Triangle_3;
|
||||
typedef typename std::vector<Triangle_3>::iterator Iterator;
|
||||
typedef CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
|
||||
typedef CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
|
||||
typedef CGAL::AABB_tree<AABB_triangle_traits> Tree;
|
||||
typedef typename Tree::Point_and_primitive_id Point_and_primitive_id;
|
||||
typedef CGAL::Point_3<Kernel> Point_3;
|
||||
assert(P.cols() == 3);
|
||||
const int n = P.rows();
|
||||
sqrD.resize(n,1);
|
||||
I.resize(n,1);
|
||||
C.resize(n,P.cols());
|
||||
for(int p = 0;p < n;p++)
|
||||
{
|
||||
Point_3 query(P(p,0),P(p,1),P(p,2));
|
||||
// Find closest point and primitive id
|
||||
Point_and_primitive_id pp = tree.closest_point_and_primitive(query);
|
||||
Point_3 closest_point = pp.first;
|
||||
assign_scalar(closest_point[0],C(p,0));
|
||||
assign_scalar(closest_point[1],C(p,1));
|
||||
assign_scalar(closest_point[2],C(p,2));
|
||||
assign_scalar((closest_point-query).squared_length(),sqrD(p));
|
||||
I(p) = pp.second - T.begin();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::copyleft::cgal::point_mesh_squared_distance<CGAL::Epeck, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::point_mesh_squared_distance<CGAL::Epeck, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
104
src/libigl/igl/copyleft/cgal/point_mesh_squared_distance.h
Normal file
104
src/libigl/igl/copyleft/cgal/point_mesh_squared_distance.h
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_POINT_MESH_SQUARED_DISTANCE_H
|
||||
#define IGL_COPYLEFT_CGAL_POINT_MESH_SQUARED_DISTANCE_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
#include "CGAL_includes.hpp"
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Compute distances from a set of points P to a triangle mesh (V,F)
|
||||
//
|
||||
// Templates:
|
||||
// Kernal CGAL computation and construction kernel (e.g.
|
||||
// CGAL::Simple_cartesian<double>)
|
||||
// Inputs:
|
||||
// P #P by 3 list of query point positions
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices
|
||||
// Outputs:
|
||||
// sqrD #P list of smallest squared distances
|
||||
// I #P list of facet indices corresponding to smallest distances
|
||||
// C #P by 3 list of closest points
|
||||
//
|
||||
// Known bugs: This only computes distances to triangles. So unreferenced
|
||||
// vertices and degenerate triangles (segments) are ignored.
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedP,
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedsqrD,
|
||||
typename DerivedI,
|
||||
typename DerivedC>
|
||||
IGL_INLINE void point_mesh_squared_distance(
|
||||
const Eigen::PlainObjectBase<DerivedP> & P,
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
|
||||
Eigen::PlainObjectBase<DerivedI> & I,
|
||||
Eigen::PlainObjectBase<DerivedC> & C);
|
||||
// Probably can do this in a way that we don't pass around `tree` and `T`
|
||||
//
|
||||
// Outputs:
|
||||
// tree CGAL's AABB tree
|
||||
// T list of CGAL triangles in order of F (for determining which was found
|
||||
// in computation)
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedV,
|
||||
typename DerivedF
|
||||
>
|
||||
IGL_INLINE void point_mesh_squared_distance_precompute(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
CGAL::AABB_tree<
|
||||
CGAL::AABB_traits<Kernel,
|
||||
CGAL::AABB_triangle_primitive<Kernel,
|
||||
typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
|
||||
>
|
||||
>
|
||||
> & tree,
|
||||
std::vector<CGAL::Triangle_3<Kernel> > & T);
|
||||
// Inputs:
|
||||
// see above
|
||||
// Outputs:
|
||||
// see above
|
||||
template <
|
||||
typename Kernel,
|
||||
typename DerivedP,
|
||||
typename DerivedsqrD,
|
||||
typename DerivedI,
|
||||
typename DerivedC>
|
||||
IGL_INLINE void point_mesh_squared_distance(
|
||||
const Eigen::PlainObjectBase<DerivedP> & P,
|
||||
const CGAL::AABB_tree<
|
||||
CGAL::AABB_traits<Kernel,
|
||||
CGAL::AABB_triangle_primitive<Kernel,
|
||||
typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
|
||||
>
|
||||
>
|
||||
> & tree,
|
||||
const std::vector<CGAL::Triangle_3<Kernel> > & T,
|
||||
Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
|
||||
Eigen::PlainObjectBase<DerivedI> & I,
|
||||
Eigen::PlainObjectBase<DerivedC> & C);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "point_mesh_squared_distance.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_POINT_SEGMENT_SQUARED_DISTANCE_H
|
||||
#define IGL_COPYLEFT_CGAL_POINT_SEGMENT_SQUARED_DISTANCE_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <CGAL/Segment_3.h>
|
||||
#include <CGAL/Point_3.h>
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Given a point P1 and segment S2 find the points on each of closest
|
||||
// approach and the squared distance thereof.
|
||||
//
|
||||
// Inputs:
|
||||
// P1 point
|
||||
// S2 segment
|
||||
// Outputs:
|
||||
// P2 point on S2 closest to P1
|
||||
// d distance betwee P1 and S2
|
||||
template < typename Kernel>
|
||||
IGL_INLINE void point_segment_squared_distance(
|
||||
const CGAL::Point_3<Kernel> & P1,
|
||||
const CGAL::Segment_3<Kernel> & S2,
|
||||
CGAL::Point_3<Kernel> & P2,
|
||||
typename Kernel::FT & d
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "point_segment_squared_distance.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "point_solid_signed_squared_distance.h"
|
||||
#include "points_inside_component.h"
|
||||
#include "point_mesh_squared_distance.h"
|
||||
#include "../../list_to_matrix.h"
|
||||
#include "../../slice_mask.h"
|
||||
#include <vector>
|
||||
#include <Eigen/Core>
|
||||
|
||||
template <
|
||||
typename DerivedQ,
|
||||
typename DerivedVB,
|
||||
typename DerivedFB,
|
||||
typename DerivedD>
|
||||
IGL_INLINE void igl::copyleft::cgal::point_solid_signed_squared_distance(
|
||||
const Eigen::PlainObjectBase<DerivedQ> & Q,
|
||||
const Eigen::PlainObjectBase<DerivedVB> & VB,
|
||||
const Eigen::PlainObjectBase<DerivedFB> & FB,
|
||||
Eigen::PlainObjectBase<DerivedD> & D)
|
||||
{
|
||||
// compute unsigned distances
|
||||
Eigen::VectorXi I;
|
||||
DerivedVB C;
|
||||
point_mesh_squared_distance<CGAL::Epeck>(Q,VB,FB,D,I,C);
|
||||
// Collect queries that have non-zero distance
|
||||
Eigen::Array<bool,Eigen::Dynamic,1> NZ = D.array()!=0;
|
||||
// Compute sign for non-zero distance queries
|
||||
DerivedQ QNZ;
|
||||
slice_mask(Q,NZ,1,QNZ);
|
||||
Eigen::Array<bool,Eigen::Dynamic,1> DNZ;
|
||||
igl::copyleft::cgal::points_inside_component(VB,FB,QNZ,DNZ);
|
||||
// Apply sign to distances
|
||||
DerivedD S = DerivedD::Zero(Q.rows(),1);
|
||||
{
|
||||
int k = 0;
|
||||
for(int q = 0;q<Q.rows();q++)
|
||||
{
|
||||
if(NZ(q))
|
||||
{
|
||||
D(q) *= DNZ(k++) ? -1. : 1.;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::point_solid_signed_squared_distance<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_POINT_TRIANGLE_SQUARED_DISTANCE_H
|
||||
#define IGL_COPYLEFT_CGAL_POINT_TRIANGLE_SQUARED_DISTANCE_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <CGAL/Triangle_3.h>
|
||||
#include <CGAL/Point_3.h>
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Given a point P1 and triangle T2 find the points on each of closest
|
||||
// approach and the squared distance thereof.
|
||||
//
|
||||
// Inputs:
|
||||
// P1 point
|
||||
// T2 triangle
|
||||
// Outputs:
|
||||
// P2 point on T2 closest to P1
|
||||
// d distance betwee P1 and T2
|
||||
template < typename Kernel>
|
||||
IGL_INLINE void point_triangle_squared_distance(
|
||||
const CGAL::Point_3<Kernel> & P1,
|
||||
const CGAL::Triangle_3<Kernel> & T2,
|
||||
CGAL::Point_3<Kernel> & P2,
|
||||
typename Kernel::FT & d
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "point_triangle_squared_distance.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
350
src/libigl/igl/copyleft/cgal/points_inside_component.cpp
Normal file
350
src/libigl/igl/copyleft/cgal/points_inside_component.cpp
Normal file
|
|
@ -0,0 +1,350 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "points_inside_component.h"
|
||||
#include "../../LinSpaced.h"
|
||||
#include "order_facets_around_edge.h"
|
||||
#include "assign_scalar.h"
|
||||
|
||||
#include <CGAL/AABB_tree.h>
|
||||
#include <CGAL/AABB_traits.h>
|
||||
#include <CGAL/AABB_triangle_primitive.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <list>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace igl {
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal {
|
||||
namespace points_inside_component_helper {
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
|
||||
typedef Kernel::Ray_3 Ray_3;
|
||||
typedef Kernel::Point_3 Point_3;
|
||||
typedef Kernel::Vector_3 Vector_3;
|
||||
typedef Kernel::Triangle_3 Triangle;
|
||||
typedef Kernel::Plane_3 Plane_3;
|
||||
typedef std::vector<Triangle>::iterator Iterator;
|
||||
typedef CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
|
||||
typedef CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
|
||||
typedef CGAL::AABB_tree<AABB_triangle_traits> Tree;
|
||||
|
||||
template<typename DerivedF, typename DerivedI>
|
||||
void extract_adj_faces(
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I,
|
||||
const size_t s, const size_t d,
|
||||
std::vector<int>& adj_faces) {
|
||||
const size_t num_faces = I.rows();
|
||||
for (size_t i=0; i<num_faces; i++) {
|
||||
Eigen::Vector3i f = F.row(I(i, 0));
|
||||
if (((size_t)f[0] == s && (size_t)f[1] == d) ||
|
||||
((size_t)f[1] == s && (size_t)f[2] == d) ||
|
||||
((size_t)f[2] == s && (size_t)f[0] == d)) {
|
||||
adj_faces.push_back((I(i, 0)+1) * -1);
|
||||
continue;
|
||||
}
|
||||
if (((size_t)f[0] == d && (size_t)f[1] == s) ||
|
||||
((size_t)f[1] == d && (size_t)f[2] == s) ||
|
||||
((size_t)f[2] == d && (size_t)f[0] == s)) {
|
||||
adj_faces.push_back(I(i, 0)+1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename DerivedF, typename DerivedI>
|
||||
void extract_adj_vertices(
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I,
|
||||
const size_t v, std::vector<int>& adj_vertices) {
|
||||
std::set<size_t> unique_adj_vertices;
|
||||
const size_t num_faces = I.rows();
|
||||
for (size_t i=0; i<num_faces; i++) {
|
||||
Eigen::Vector3i f = F.row(I(i, 0));
|
||||
if ((size_t)f[0] == v) {
|
||||
unique_adj_vertices.insert(f[1]);
|
||||
unique_adj_vertices.insert(f[2]);
|
||||
} else if ((size_t)f[1] == v) {
|
||||
unique_adj_vertices.insert(f[0]);
|
||||
unique_adj_vertices.insert(f[2]);
|
||||
} else if ((size_t)f[2] == v) {
|
||||
unique_adj_vertices.insert(f[0]);
|
||||
unique_adj_vertices.insert(f[1]);
|
||||
}
|
||||
}
|
||||
adj_vertices.resize(unique_adj_vertices.size());
|
||||
std::copy(unique_adj_vertices.begin(),
|
||||
unique_adj_vertices.end(),
|
||||
adj_vertices.begin());
|
||||
}
|
||||
|
||||
template<typename DerivedV, typename DerivedF, typename DerivedI>
|
||||
bool determine_point_edge_orientation(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I,
|
||||
const Point_3& query, size_t s, size_t d) {
|
||||
// Algorithm:
|
||||
//
|
||||
// Order the adj faces around the edge (s,d) clockwise using
|
||||
// query point as pivot. (i.e. The first face of the ordering
|
||||
// is directly after the pivot point, and the last face is
|
||||
// directly before the pivot.)
|
||||
//
|
||||
// The point is outside if the first and last faces of the
|
||||
// ordering forms a convex angle. This check can be done
|
||||
// without any construction by looking at the orientation of the
|
||||
// faces. The angle is convex iff the first face contains (s,d)
|
||||
// as an edge and the last face contains (d,s) as an edge.
|
||||
//
|
||||
// The point is inside if the first and last faces of the
|
||||
// ordering forms a concave angle. That is the first face
|
||||
// contains (d,s) as an edge and the last face contains (s,d) as
|
||||
// an edge.
|
||||
//
|
||||
// In the special case of duplicated faces. I.e. multiple faces
|
||||
// sharing the same 3 corners, but not necessarily the same
|
||||
// orientation. The ordering will always rank faces containing
|
||||
// edge (s,d) before faces containing edge (d,s).
|
||||
//
|
||||
// Therefore, if there are any duplicates of the first faces,
|
||||
// the ordering will always choose the one with edge (s,d) if
|
||||
// possible. The same for the last face.
|
||||
//
|
||||
// In the very degenerated case where the first and last face
|
||||
// are duplicates, but with different orientations, it is
|
||||
// equally valid to think the angle formed by them is either 0
|
||||
// or 360 degrees. By default, 0 degree is used, and thus the
|
||||
// query point is outside.
|
||||
|
||||
std::vector<int> adj_faces;
|
||||
extract_adj_faces(F, I, s, d, adj_faces);
|
||||
const size_t num_adj_faces = adj_faces.size();
|
||||
assert(num_adj_faces > 0);
|
||||
|
||||
DerivedV pivot_point(1, 3);
|
||||
igl::copyleft::cgal::assign_scalar(query.x(), pivot_point(0, 0));
|
||||
igl::copyleft::cgal::assign_scalar(query.y(), pivot_point(0, 1));
|
||||
igl::copyleft::cgal::assign_scalar(query.z(), pivot_point(0, 2));
|
||||
Eigen::VectorXi order;
|
||||
order_facets_around_edge(V, F, s, d,
|
||||
adj_faces, pivot_point, order);
|
||||
assert((size_t)order.size() == num_adj_faces);
|
||||
if (adj_faces[order[0]] > 0 &&
|
||||
adj_faces[order[num_adj_faces-1] < 0]) {
|
||||
return true;
|
||||
} else if (adj_faces[order[0]] < 0 &&
|
||||
adj_faces[order[num_adj_faces-1] > 0]) {
|
||||
return false;
|
||||
} else {
|
||||
throw "The input mesh does not represent a valid volume";
|
||||
}
|
||||
throw "The input mesh does not represent a valid volume";
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename DerivedV, typename DerivedF, typename DerivedI>
|
||||
bool determine_point_vertex_orientation(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I,
|
||||
const Point_3& query, size_t s) {
|
||||
std::vector<int> adj_vertices;
|
||||
extract_adj_vertices(F, I, s, adj_vertices);
|
||||
const size_t num_adj_vertices = adj_vertices.size();
|
||||
|
||||
std::vector<Point_3> adj_points;
|
||||
for (size_t i=0; i<num_adj_vertices; i++) {
|
||||
const size_t vi = adj_vertices[i];
|
||||
adj_points.emplace_back(V(vi,0), V(vi,1), V(vi,2));
|
||||
}
|
||||
|
||||
// A plane is on the exterior if all adj_points lies on or to
|
||||
// one side of the plane.
|
||||
auto is_on_exterior = [&](const Plane_3& separator) -> bool{
|
||||
size_t positive=0;
|
||||
size_t negative=0;
|
||||
size_t coplanar=0;
|
||||
for (const auto& point : adj_points) {
|
||||
switch(separator.oriented_side(point)) {
|
||||
case CGAL::ON_POSITIVE_SIDE:
|
||||
positive++;
|
||||
break;
|
||||
case CGAL::ON_NEGATIVE_SIDE:
|
||||
negative++;
|
||||
break;
|
||||
case CGAL::ON_ORIENTED_BOUNDARY:
|
||||
coplanar++;
|
||||
break;
|
||||
default:
|
||||
throw "Unknown plane-point orientation";
|
||||
}
|
||||
}
|
||||
auto query_orientation = separator.oriented_side(query);
|
||||
bool r =
|
||||
(positive == 0 && query_orientation == CGAL::POSITIVE)
|
||||
||
|
||||
(negative == 0 && query_orientation == CGAL::NEGATIVE);
|
||||
return r;
|
||||
};
|
||||
|
||||
size_t d = std::numeric_limits<size_t>::max();
|
||||
Point_3 p(V(s,0), V(s,1), V(s,2));
|
||||
for (size_t i=0; i<num_adj_vertices; i++) {
|
||||
const size_t vi = adj_vertices[i];
|
||||
for (size_t j=i+1; j<num_adj_vertices; j++) {
|
||||
Plane_3 separator(p, adj_points[i], adj_points[j]);
|
||||
if (separator.is_degenerate()) {
|
||||
throw "Input mesh contains degenerated faces";
|
||||
}
|
||||
if (is_on_exterior(separator)) {
|
||||
d = vi;
|
||||
assert(!CGAL::collinear(p, adj_points[i], query));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (d < (size_t)V.rows()) break;
|
||||
}
|
||||
if (d > (size_t)V.rows()) {
|
||||
// All adj faces are coplanar, use the first edge.
|
||||
d = adj_vertices[0];
|
||||
}
|
||||
return determine_point_edge_orientation(V, F, I, query, s, d);
|
||||
}
|
||||
|
||||
template<typename DerivedV, typename DerivedF, typename DerivedI>
|
||||
bool determine_point_face_orientation(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I,
|
||||
const Point_3& query, size_t fid) {
|
||||
// Algorithm: A point is on the inside of a face if the
|
||||
// tetrahedron formed by them is negatively oriented.
|
||||
|
||||
Eigen::Vector3i f = F.row(I(fid, 0));
|
||||
const Point_3 v0(V(f[0], 0), V(f[0], 1), V(f[0], 2));
|
||||
const Point_3 v1(V(f[1], 0), V(f[1], 1), V(f[1], 2));
|
||||
const Point_3 v2(V(f[2], 0), V(f[2], 1), V(f[2], 2));
|
||||
auto result = CGAL::orientation(v0, v1, v2, query);
|
||||
if (result == CGAL::COPLANAR) {
|
||||
throw "Cannot determine inside/outside because query point lies exactly on the input surface.";
|
||||
}
|
||||
return result == CGAL::NEGATIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename DerivedV, typename DerivedF, typename DerivedI,
|
||||
typename DerivedP, typename DerivedB>
|
||||
IGL_INLINE void igl::copyleft::cgal::points_inside_component(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
Eigen::PlainObjectBase<DerivedB>& inside) {
|
||||
using namespace igl::copyleft::cgal::points_inside_component_helper;
|
||||
if (F.rows() <= 0 || I.rows() <= 0) {
|
||||
throw "Inside check cannot be done on empty facet component.";
|
||||
}
|
||||
|
||||
const size_t num_faces = I.rows();
|
||||
std::vector<Triangle> triangles;
|
||||
for (size_t i=0; i<num_faces; i++) {
|
||||
const Eigen::Vector3i f = F.row(I(i, 0));
|
||||
triangles.emplace_back(
|
||||
Point_3(V(f[0], 0), V(f[0], 1), V(f[0], 2)),
|
||||
Point_3(V(f[1], 0), V(f[1], 1), V(f[1], 2)),
|
||||
Point_3(V(f[2], 0), V(f[2], 1), V(f[2], 2)));
|
||||
if (triangles.back().is_degenerate()) {
|
||||
throw "Input facet components contains degenerated triangles";
|
||||
}
|
||||
}
|
||||
Tree tree(triangles.begin(), triangles.end());
|
||||
tree.accelerate_distance_queries();
|
||||
|
||||
enum ElementType { VERTEX, EDGE, FACE };
|
||||
auto determine_element_type = [&](
|
||||
size_t fid, const Point_3& p, size_t& element_index) -> ElementType{
|
||||
const Eigen::Vector3i f = F.row(I(fid, 0));
|
||||
const Point_3 p0(V(f[0], 0), V(f[0], 1), V(f[0], 2));
|
||||
const Point_3 p1(V(f[1], 0), V(f[1], 1), V(f[1], 2));
|
||||
const Point_3 p2(V(f[2], 0), V(f[2], 1), V(f[2], 2));
|
||||
|
||||
if (p == p0) { element_index = 0; return VERTEX; }
|
||||
if (p == p1) { element_index = 1; return VERTEX; }
|
||||
if (p == p2) { element_index = 2; return VERTEX; }
|
||||
if (CGAL::collinear(p0, p1, p)) { element_index = 2; return EDGE; }
|
||||
if (CGAL::collinear(p1, p2, p)) { element_index = 0; return EDGE; }
|
||||
if (CGAL::collinear(p2, p0, p)) { element_index = 1; return EDGE; }
|
||||
|
||||
element_index = 0;
|
||||
return FACE;
|
||||
};
|
||||
|
||||
const size_t num_queries = P.rows();
|
||||
inside.resize(num_queries, 1);
|
||||
for (size_t i=0; i<num_queries; i++) {
|
||||
const Point_3 query(P(i,0), P(i,1), P(i,2));
|
||||
auto projection = tree.closest_point_and_primitive(query);
|
||||
auto closest_point = projection.first;
|
||||
size_t fid = projection.second - triangles.begin();
|
||||
|
||||
size_t element_index;
|
||||
switch (determine_element_type(fid, closest_point, element_index)) {
|
||||
case VERTEX:
|
||||
{
|
||||
const size_t s = F(I(fid, 0), element_index);
|
||||
inside(i,0) = determine_point_vertex_orientation(
|
||||
V, F, I, query, s);
|
||||
}
|
||||
break;
|
||||
case EDGE:
|
||||
{
|
||||
const size_t s = F(I(fid, 0), (element_index+1)%3);
|
||||
const size_t d = F(I(fid, 0), (element_index+2)%3);
|
||||
inside(i,0) = determine_point_edge_orientation(
|
||||
V, F, I, query, s, d);
|
||||
}
|
||||
break;
|
||||
case FACE:
|
||||
inside(i,0) = determine_point_face_orientation(V, F, I, query, fid);
|
||||
break;
|
||||
default:
|
||||
throw "Unknown closest element type!";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename DerivedV, typename DerivedF, typename DerivedP,
|
||||
typename DerivedB>
|
||||
IGL_INLINE void igl::copyleft::cgal::points_inside_component(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
Eigen::PlainObjectBase<DerivedB>& inside) {
|
||||
Eigen::VectorXi I = igl::LinSpaced<Eigen::VectorXi>(F.rows(), 0, F.rows()-1);
|
||||
igl::copyleft::cgal::points_inside_component(V, F, I, P, inside);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::points_inside_component<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Array<bool, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Array<bool, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::points_inside_component< Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix< int, -1, -1, 0, -1, -1>, Eigen::Matrix< int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix< int, -1, -1, 0, -1, -1> > ( Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::points_inside_component< Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix< int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix< int, -1, -1, 0, -1, -1> > ( Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::points_inside_component<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::points_inside_component<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::points_inside_component<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::copyleft::cgal::points_inside_component<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
71
src/libigl/igl/copyleft/cgal/points_inside_component.h
Normal file
71
src/libigl/igl/copyleft/cgal/points_inside_component.h
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_POINTS_INSIDE_COMPONENTS
|
||||
#define IGL_COPYLEFT_CGAL_POINTS_INSIDE_COMPONENTS
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal {
|
||||
|
||||
// Determine if queries points P are inside of connected facet component
|
||||
// (V, F, I), where I indicates a subset of facets that forms the
|
||||
// component.
|
||||
//
|
||||
// Precondition:
|
||||
// The input mesh must be a closed, self-intersection free,
|
||||
// non-degenerated surface. Queries points must be either inside or
|
||||
// outside of the mesh (i.e. not on the surface of the mesh).
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 array of vertex positions.
|
||||
// F #F by 3 array of triangles.
|
||||
// I #I list of triangle indices to consider.
|
||||
// P #P by 3 array of query points.
|
||||
//
|
||||
// Outputs:
|
||||
// inside #P list of booleans that is true iff the corresponding
|
||||
// query point is inside of the mesh.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedI,
|
||||
typename DerivedP,
|
||||
typename DerivedB>
|
||||
IGL_INLINE void points_inside_component(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedI>& I,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
Eigen::PlainObjectBase<DerivedB>& inside);
|
||||
|
||||
// Determine if query points P is inside of the mesh (V, F).
|
||||
// See above for precondition and I/O specs.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename DerivedB>
|
||||
IGL_INLINE void points_inside_component(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
Eigen::PlainObjectBase<DerivedB>& inside);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
#include "points_inside_component.cpp"
|
||||
#endif
|
||||
#endif
|
||||
69
src/libigl/igl/copyleft/cgal/polyhedron_to_mesh.cpp
Normal file
69
src/libigl/igl/copyleft/cgal/polyhedron_to_mesh.cpp
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "polyhedron_to_mesh.h"
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
|
||||
template <
|
||||
typename Polyhedron,
|
||||
typename DerivedV,
|
||||
typename DerivedF>
|
||||
IGL_INLINE void igl::copyleft::cgal::polyhedron_to_mesh(
|
||||
const Polyhedron & poly,
|
||||
Eigen::PlainObjectBase<DerivedV> & V,
|
||||
Eigen::PlainObjectBase<DerivedF> & F)
|
||||
{
|
||||
using namespace std;
|
||||
V.resize(poly.size_of_vertices(),3);
|
||||
F.resize(poly.size_of_facets(),3);
|
||||
typedef typename Polyhedron::Vertex_const_iterator Vertex_iterator;
|
||||
std::map<Vertex_iterator,size_t> vertex_to_index;
|
||||
{
|
||||
size_t v = 0;
|
||||
for(
|
||||
typename Polyhedron::Vertex_const_iterator p = poly.vertices_begin();
|
||||
p != poly.vertices_end();
|
||||
p++)
|
||||
{
|
||||
V(v,0) = p->point().x();
|
||||
V(v,1) = p->point().y();
|
||||
V(v,2) = p->point().z();
|
||||
vertex_to_index[p] = v;
|
||||
v++;
|
||||
}
|
||||
}
|
||||
{
|
||||
size_t f = 0;
|
||||
for(
|
||||
typename Polyhedron::Facet_const_iterator facet = poly.facets_begin();
|
||||
facet != poly.facets_end();
|
||||
++facet)
|
||||
{
|
||||
typename Polyhedron::Halfedge_around_facet_const_circulator he =
|
||||
facet->facet_begin();
|
||||
// Facets in polyhedral surfaces are at least triangles.
|
||||
assert(CGAL::circulator_size(he) == 3 && "Facets should be triangles");
|
||||
size_t c = 0;
|
||||
do {
|
||||
//// This is stooopidly slow
|
||||
// F(f,c) = std::distance(poly.vertices_begin(), he->vertex());
|
||||
F(f,c) = vertex_to_index[he->vertex()];
|
||||
c++;
|
||||
} while ( ++he != facet->facet_begin());
|
||||
f++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Polyhedron_items_with_id_3.h>
|
||||
template void igl::copyleft::cgal::polyhedron_to_mesh<CGAL::Polyhedron_3<CGAL::Epick, CGAL::Polyhedron_items_3, CGAL::HalfedgeDS_default, std::allocator<int> >, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(CGAL::Polyhedron_3<CGAL::Epick, CGAL::Polyhedron_items_3, CGAL::HalfedgeDS_default, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::copyleft::cgal::polyhedron_to_mesh<CGAL::Polyhedron_3<CGAL::Simple_cartesian<double>,CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator<int> >, Eigen::Matrix<double, -1, -1, 0,-1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(CGAL::Polyhedron_3<CGAL::Simple_cartesian<double>,CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator<int> > const&,Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0,-1, -1> >&);
|
||||
#endif
|
||||
43
src/libigl/igl/copyleft/cgal/polyhedron_to_mesh.h
Normal file
43
src/libigl/igl/copyleft/cgal/polyhedron_to_mesh.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_POLYHEDRON_TO_MESH_H
|
||||
#define IGL_COPYLEFT_CGAL_POLYHEDRON_TO_MESH_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Convert a CGAL Polyhedron to a mesh (V,F)
|
||||
//
|
||||
// Templates:
|
||||
// Polyhedron CGAL Polyhedron type (e.g. Polyhedron_3)
|
||||
// Inputs:
|
||||
// poly cgal polyhedron
|
||||
// Outputs:
|
||||
// V #V by 3 list of vertex positions
|
||||
// F #F by 3 list of triangle indices
|
||||
template <
|
||||
typename Polyhedron,
|
||||
typename DerivedV,
|
||||
typename DerivedF>
|
||||
IGL_INLINE void polyhedron_to_mesh(
|
||||
const Polyhedron & poly,
|
||||
Eigen::PlainObjectBase<DerivedV> & V,
|
||||
Eigen::PlainObjectBase<DerivedF> & F);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "polyhedron_to_mesh.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
82
src/libigl/igl/copyleft/cgal/projected_cdt.cpp
Normal file
82
src/libigl/igl/copyleft/cgal/projected_cdt.cpp
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "projected_cdt.h"
|
||||
#include "insert_into_cdt.h"
|
||||
#include "assign_scalar.h"
|
||||
#include "../../list_to_matrix.h"
|
||||
template <typename Kernel, typename Index>
|
||||
IGL_INLINE void igl::copyleft::cgal::projected_cdt(
|
||||
const std::vector<CGAL::Object> & objects,
|
||||
const CGAL::Plane_3<Kernel> & P,
|
||||
std::vector<CGAL::Point_3<Kernel> >& vertices,
|
||||
std::vector<std::vector<Index> >& faces)
|
||||
{
|
||||
typedef CGAL::Triangulation_vertex_base_2<Kernel> TVB_2;
|
||||
typedef CGAL::Constrained_triangulation_face_base_2<Kernel> CTFB_2;
|
||||
typedef CGAL::Triangulation_data_structure_2<TVB_2,CTFB_2> TDS_2;
|
||||
typedef CGAL::Exact_intersections_tag Itag;
|
||||
typedef CGAL::Constrained_Delaunay_triangulation_2<Kernel,TDS_2,Itag> CDT_2;
|
||||
typedef CGAL::Constrained_triangulation_plus_2<CDT_2> CDT_plus_2;
|
||||
CDT_plus_2 cdt;
|
||||
for(const auto & obj : objects) insert_into_cdt(obj,P,cdt);
|
||||
// Read off vertices of the cdt, remembering index
|
||||
std::map<typename CDT_plus_2::Vertex_handle,Index> v2i;
|
||||
size_t count=0;
|
||||
for (
|
||||
auto itr = cdt.finite_vertices_begin();
|
||||
itr != cdt.finite_vertices_end();
|
||||
itr++)
|
||||
{
|
||||
vertices.push_back(P.to_3d(itr->point()));
|
||||
v2i[itr] = count;
|
||||
count++;
|
||||
}
|
||||
// Read off faces and store index triples
|
||||
for (
|
||||
auto itr = cdt.finite_faces_begin();
|
||||
itr != cdt.finite_faces_end();
|
||||
itr++)
|
||||
{
|
||||
faces.push_back(
|
||||
{ v2i[itr->vertex(0)], v2i[itr->vertex(1)], v2i[itr->vertex(2)] });
|
||||
}
|
||||
}
|
||||
|
||||
template < typename Kernel, typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE void igl::copyleft::cgal::projected_cdt(
|
||||
const std::vector<CGAL::Object> & objects,
|
||||
const CGAL::Plane_3<Kernel> & P,
|
||||
Eigen::PlainObjectBase<DerivedV> & V,
|
||||
Eigen::PlainObjectBase<DerivedF> & F)
|
||||
{
|
||||
std::vector<CGAL::Point_3<Kernel> > vertices;
|
||||
std::vector<std::vector<typename DerivedF::Scalar> > faces;
|
||||
projected_cdt(objects,P,vertices,faces);
|
||||
V.resize(vertices.size(),3);
|
||||
for(int v = 0;v<vertices.size();v++)
|
||||
{
|
||||
for(int d = 0;d<3;d++)
|
||||
{
|
||||
assign_scalar(vertices[v][d], V(v,d));
|
||||
}
|
||||
}
|
||||
list_to_matrix(faces,F);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::projected_cdt<CGAL::Epick, long>(std::vector<CGAL::Object, std::allocator<CGAL::Object> > const&, CGAL::Plane_3<CGAL::Epick> const&, std::vector<CGAL::Point_3<CGAL::Epick>, std::allocator<CGAL::Point_3<CGAL::Epick> > >&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::copyleft::cgal::projected_cdt<CGAL::Epeck, long>(std::vector<CGAL::Object, std::allocator<CGAL::Object> > const&, CGAL::Plane_3<CGAL::Epeck> const&, std::vector<CGAL::Point_3<CGAL::Epeck>, std::allocator<CGAL::Point_3<CGAL::Epeck> > >&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&);
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#ifdef WIN32
|
||||
template void igl::copyleft::cgal::projected_cdt<class CGAL::Epeck, __int64>(class std::vector<class CGAL::Object, class std::allocator<class CGAL::Object>> const &, class CGAL::Plane_3<class CGAL::Epeck> const &, class std::vector<class CGAL::Point_3<class CGAL::Epeck>, class std::allocator<class CGAL::Point_3<class CGAL::Epeck>>> &, class std::vector<class std::vector<__int64, class std::allocator<__int64>>, class std::allocator<class std::vector<__int64, class std::allocator<__int64>>>> &);
|
||||
template void igl::copyleft::cgal::projected_cdt<class CGAL::Epick, __int64>(class std::vector<class CGAL::Object, class std::allocator<class CGAL::Object>> const &, class CGAL::Plane_3<class CGAL::Epick> const &, class std::vector<class CGAL::Point_3<class CGAL::Epick>, class std::allocator<class CGAL::Point_3<class CGAL::Epick>>> &, class std::vector<class std::vector<__int64, class std::allocator<__int64>>, class std::allocator<class std::vector<__int64, class std::allocator<__int64>>>> &);
|
||||
#endif
|
||||
#endif
|
||||
61
src/libigl/igl/copyleft/cgal/projected_cdt.h
Normal file
61
src/libigl/igl/copyleft/cgal/projected_cdt.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_PROJECTED_CDT_H
|
||||
#define IGL_COPYLEFT_CGAL_PROJECTED_CDT_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <CGAL/Plane_3.h>
|
||||
#include <CGAL/Point_3.h>
|
||||
#include <CGAL/Object.h>
|
||||
#include <vector>
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Given a list of objects (e.g., resulting from intersecting a triangle
|
||||
// with many other triangles), construct a constrained Delaunay
|
||||
// triangulation on a given plane (P), by inersting constraints for each
|
||||
// object projected onto that plane.
|
||||
//
|
||||
// Inputs:
|
||||
// objects list of objects. This should lie on the given plane (P),
|
||||
// otherwise they are added to the cdt _after_ their non-trivial
|
||||
// projection
|
||||
// P plane upon which all objects lie and upon which the CDT is
|
||||
// conducted
|
||||
// Outputs:
|
||||
// vertices list of vertices of the CDT mesh _back on the 3D plane_
|
||||
// faces list of list of triangle indices into vertices
|
||||
//
|
||||
template <typename Kernel, typename Index>
|
||||
IGL_INLINE void projected_cdt(
|
||||
const std::vector<CGAL::Object> & objects,
|
||||
const CGAL::Plane_3<Kernel> & P,
|
||||
std::vector<CGAL::Point_3<Kernel> >& vertices,
|
||||
std::vector<std::vector<Index> >& faces);
|
||||
// Outputs:
|
||||
// V #V by 3 list of vertices of the CDT mesh _back on the 3D plane_,
|
||||
// **cast** from the number type of Kernel to the number type of
|
||||
// DerivedV
|
||||
// F #F by 3 list of triangle indices into V
|
||||
template < typename Kernel, typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE void projected_cdt(
|
||||
const std::vector<CGAL::Object> & objects,
|
||||
const CGAL::Plane_3<Kernel> & P,
|
||||
Eigen::PlainObjectBase<DerivedV> & V,
|
||||
Eigen::PlainObjectBase<DerivedF> & F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "projected_cdt.cpp"
|
||||
#endif
|
||||
#endif
|
||||
106
src/libigl/igl/copyleft/cgal/projected_delaunay.cpp
Normal file
106
src/libigl/igl/copyleft/cgal/projected_delaunay.cpp
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "projected_delaunay.h"
|
||||
#include "../../REDRUM.h"
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
#if CGAL_VERSION_NR < 1040611000
|
||||
# warning "CGAL Version < 4.6.1 may result in crashes. Please upgrade CGAL"
|
||||
#endif
|
||||
|
||||
template <typename Kernel>
|
||||
IGL_INLINE void igl::copyleft::cgal::projected_delaunay(
|
||||
const CGAL::Triangle_3<Kernel> & A,
|
||||
const std::vector<CGAL::Object> & A_objects_3,
|
||||
CGAL::Constrained_triangulation_plus_2<
|
||||
CGAL::Constrained_Delaunay_triangulation_2<
|
||||
Kernel,
|
||||
CGAL::Triangulation_data_structure_2<
|
||||
CGAL::Triangulation_vertex_base_2<Kernel>,
|
||||
CGAL::Constrained_triangulation_face_base_2<Kernel> >,
|
||||
CGAL::Exact_intersections_tag> > & cdt)
|
||||
{
|
||||
using namespace std;
|
||||
// 3D Primitives
|
||||
typedef CGAL::Point_3<Kernel> Point_3;
|
||||
typedef CGAL::Segment_3<Kernel> Segment_3;
|
||||
typedef CGAL::Triangle_3<Kernel> Triangle_3;
|
||||
typedef CGAL::Plane_3<Kernel> Plane_3;
|
||||
//typedef CGAL::Tetrahedron_3<Kernel> Tetrahedron_3;
|
||||
typedef CGAL::Point_2<Kernel> Point_2;
|
||||
//typedef CGAL::Segment_2<Kernel> Segment_2;
|
||||
//typedef CGAL::Triangle_2<Kernel> Triangle_2;
|
||||
typedef CGAL::Triangulation_vertex_base_2<Kernel> TVB_2;
|
||||
typedef CGAL::Constrained_triangulation_face_base_2<Kernel> CTFB_2;
|
||||
typedef CGAL::Triangulation_data_structure_2<TVB_2,CTFB_2> TDS_2;
|
||||
typedef CGAL::Exact_intersections_tag Itag;
|
||||
typedef CGAL::Constrained_Delaunay_triangulation_2<Kernel,TDS_2,Itag>
|
||||
CDT_2;
|
||||
typedef CGAL::Constrained_triangulation_plus_2<CDT_2> CDT_plus_2;
|
||||
|
||||
// http://www.cgal.org/Manual/3.2/doc_html/cgal_manual/Triangulation_2/Chapter_main.html#Section_2D_Triangulations_Constrained_Plus
|
||||
// Plane of triangle A
|
||||
Plane_3 P(A.vertex(0),A.vertex(1),A.vertex(2));
|
||||
// Insert triangle into vertices
|
||||
typename CDT_plus_2::Vertex_handle corners[3];
|
||||
typedef size_t Index;
|
||||
for(Index i = 0;i<3;i++)
|
||||
{
|
||||
const Point_3 & p3 = A.vertex(i);
|
||||
const Point_2 & p2 = P.to_2d(p3);
|
||||
typename CDT_plus_2::Vertex_handle corner = cdt.insert(p2);
|
||||
corners[i] = corner;
|
||||
}
|
||||
// Insert triangle edges as constraints
|
||||
for(Index i = 0;i<3;i++)
|
||||
{
|
||||
cdt.insert_constraint( corners[(i+1)%3], corners[(i+2)%3]);
|
||||
}
|
||||
// Insert constraints for intersection objects
|
||||
for( const auto & obj : A_objects_3)
|
||||
{
|
||||
if(const Segment_3 *iseg = CGAL::object_cast<Segment_3 >(&obj))
|
||||
{
|
||||
// Add segment constraint
|
||||
cdt.insert_constraint(P.to_2d(iseg->vertex(0)),P.to_2d(iseg->vertex(1)));
|
||||
}else if(const Point_3 *ipoint = CGAL::object_cast<Point_3 >(&obj))
|
||||
{
|
||||
// Add point
|
||||
cdt.insert(P.to_2d(*ipoint));
|
||||
} else if(const Triangle_3 *itri = CGAL::object_cast<Triangle_3 >(&obj))
|
||||
{
|
||||
// Add 3 segment constraints
|
||||
cdt.insert_constraint(P.to_2d(itri->vertex(0)),P.to_2d(itri->vertex(1)));
|
||||
cdt.insert_constraint(P.to_2d(itri->vertex(1)),P.to_2d(itri->vertex(2)));
|
||||
cdt.insert_constraint(P.to_2d(itri->vertex(2)),P.to_2d(itri->vertex(0)));
|
||||
} else if(const std::vector<Point_3 > *polyp =
|
||||
CGAL::object_cast< std::vector<Point_3 > >(&obj))
|
||||
{
|
||||
//cerr<<REDRUM("Poly...")<<endl;
|
||||
const std::vector<Point_3 > & poly = *polyp;
|
||||
const Index m = poly.size();
|
||||
assert(m>=2);
|
||||
for(Index p = 0;p<m;p++)
|
||||
{
|
||||
const Index np = (p+1)%m;
|
||||
cdt.insert_constraint(P.to_2d(poly[p]),P.to_2d(poly[np]));
|
||||
}
|
||||
}else
|
||||
{
|
||||
cerr<<REDRUM("What is this object?!")<<endl;
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::copyleft::cgal::projected_delaunay<CGAL::Epeck>(CGAL::Triangle_3<CGAL::Epeck> const&, std::vector<CGAL::Object, std::allocator<CGAL::Object> > const&, CGAL::Constrained_triangulation_plus_2<CGAL::Constrained_Delaunay_triangulation_2<CGAL::Epeck, CGAL::Triangulation_data_structure_2<CGAL::Triangulation_vertex_base_2<CGAL::Epeck, CGAL::Triangulation_ds_vertex_base_2<void> >, CGAL::Constrained_triangulation_face_base_2<CGAL::Epeck, CGAL::Triangulation_face_base_2<CGAL::Epeck, CGAL::Triangulation_ds_face_base_2<void> > > >, CGAL::Exact_intersections_tag> >&);
|
||||
template void igl::copyleft::cgal::projected_delaunay<CGAL::Epick>(CGAL::Triangle_3<CGAL::Epick> const&, std::vector<CGAL::Object, std::allocator<CGAL::Object> > const&, CGAL::Constrained_triangulation_plus_2<CGAL::Constrained_Delaunay_triangulation_2<CGAL::Epick, CGAL::Triangulation_data_structure_2<CGAL::Triangulation_vertex_base_2<CGAL::Epick, CGAL::Triangulation_ds_vertex_base_2<void> >, CGAL::Constrained_triangulation_face_base_2<CGAL::Epick, CGAL::Triangulation_face_base_2<CGAL::Epick, CGAL::Triangulation_ds_face_base_2<void> > > >, CGAL::Exact_intersections_tag> >&);
|
||||
#endif
|
||||
46
src/libigl/igl/copyleft/cgal/projected_delaunay.h
Normal file
46
src/libigl/igl/copyleft/cgal/projected_delaunay.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_PROJECTED_DELAUNAY_H
|
||||
#define IGL_COPYLEFT_CGAL_PROJECTED_DELAUNAY_H
|
||||
#include "../../igl_inline.h"
|
||||
#include "CGAL_includes.hpp"
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Compute 2D delaunay triangulation of a given 3d triangle and a list of
|
||||
// intersection objects (points,segments,triangles). CGAL uses an affine
|
||||
// projection rather than an isometric projection, so we're not guaranteed
|
||||
// that the 2D delaunay triangulation here will be a delaunay triangulation
|
||||
// in 3D.
|
||||
//
|
||||
// Inputs:
|
||||
// A triangle in 3D
|
||||
// A_objects_3 updated list of intersection objects for A
|
||||
// Outputs:
|
||||
// cdt Contrained delaunay triangulation in projected 2D plane
|
||||
template <typename Kernel>
|
||||
IGL_INLINE void projected_delaunay(
|
||||
const CGAL::Triangle_3<Kernel> & A,
|
||||
const std::vector<CGAL::Object> & A_objects_3,
|
||||
CGAL::Constrained_triangulation_plus_2<
|
||||
CGAL::Constrained_Delaunay_triangulation_2<
|
||||
Kernel,
|
||||
CGAL::Triangulation_data_structure_2<
|
||||
CGAL::Triangulation_vertex_base_2<Kernel>,
|
||||
CGAL::Constrained_triangulation_face_base_2<Kernel> >,
|
||||
CGAL::Exact_intersections_tag> > & cdt);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "projected_delaunay.cpp"
|
||||
#endif
|
||||
#endif
|
||||
324
src/libigl/igl/copyleft/cgal/propagate_winding_numbers.cpp
Normal file
324
src/libigl/igl/copyleft/cgal/propagate_winding_numbers.cpp
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
#include "propagate_winding_numbers.h"
|
||||
#include "../../extract_manifold_patches.h"
|
||||
#include "../../extract_non_manifold_edge_curves.h"
|
||||
#include "../../facet_components.h"
|
||||
#include "../../unique_edge_map.h"
|
||||
#include "../../piecewise_constant_winding_number.h"
|
||||
#include "../../writeOBJ.h"
|
||||
#include "../../writePLY.h"
|
||||
#include "../../get_seconds.h"
|
||||
#include "../../LinSpaced.h"
|
||||
#include "order_facets_around_edge.h"
|
||||
#include "outer_facet.h"
|
||||
#include "closest_facet.h"
|
||||
#include "assign.h"
|
||||
#include "extract_cells.h"
|
||||
#include "cell_adjacency.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <queue>
|
||||
|
||||
//#define PROPAGATE_WINDING_NUMBER_TIMING
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedL,
|
||||
typename DerivedW>
|
||||
IGL_INLINE bool igl::copyleft::cgal::propagate_winding_numbers(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedL>& labels,
|
||||
Eigen::PlainObjectBase<DerivedW>& W)
|
||||
{
|
||||
#ifdef PROPAGATE_WINDING_NUMBER_TIMING
|
||||
const auto & tictoc = []() -> double
|
||||
{
|
||||
static double t_start = igl::get_seconds();
|
||||
double diff = igl::get_seconds()-t_start;
|
||||
t_start += diff;
|
||||
return diff;
|
||||
};
|
||||
const auto log_time = [&](const std::string& label) -> void {
|
||||
std::cout << "propagate_winding_num." << label << ": "
|
||||
<< tictoc() << std::endl;
|
||||
};
|
||||
tictoc();
|
||||
#endif
|
||||
|
||||
Eigen::MatrixXi E, uE;
|
||||
Eigen::VectorXi EMAP;
|
||||
std::vector<std::vector<size_t> > uE2E;
|
||||
igl::unique_edge_map(F, E, uE, EMAP, uE2E);
|
||||
|
||||
Eigen::VectorXi P;
|
||||
const size_t num_patches = igl::extract_manifold_patches(F, EMAP, uE2E, P);
|
||||
|
||||
DerivedW per_patch_cells;
|
||||
const size_t num_cells =
|
||||
igl::copyleft::cgal::extract_cells(
|
||||
V, F, P, E, uE, uE2E, EMAP, per_patch_cells);
|
||||
#ifdef PROPAGATE_WINDING_NUMBER_TIMING
|
||||
log_time("cell_extraction");
|
||||
#endif
|
||||
|
||||
return propagate_winding_numbers(V, F,
|
||||
uE, uE2E,
|
||||
num_patches, P,
|
||||
num_cells, per_patch_cells,
|
||||
labels, W);
|
||||
}
|
||||
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename DerivedP,
|
||||
typename DerivedC,
|
||||
typename DerivedL,
|
||||
typename DerivedW>
|
||||
IGL_INLINE bool igl::copyleft::cgal::propagate_winding_numbers(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const size_t num_patches,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const size_t num_cells,
|
||||
const Eigen::PlainObjectBase<DerivedC>& C,
|
||||
const Eigen::PlainObjectBase<DerivedL>& labels,
|
||||
Eigen::PlainObjectBase<DerivedW>& W)
|
||||
{
|
||||
#ifdef PROPAGATE_WINDING_NUMBER_TIMING
|
||||
const auto & tictoc = []() -> double
|
||||
{
|
||||
static double t_start = igl::get_seconds();
|
||||
double diff = igl::get_seconds()-t_start;
|
||||
t_start += diff;
|
||||
return diff;
|
||||
};
|
||||
const auto log_time = [&](const std::string& label) -> void {
|
||||
std::cout << "propagate_winding_num." << label << ": "
|
||||
<< tictoc() << std::endl;
|
||||
};
|
||||
tictoc();
|
||||
#endif
|
||||
|
||||
bool valid = true;
|
||||
// https://github.com/libigl/libigl/issues/674
|
||||
if (!igl::piecewise_constant_winding_number(F, uE, uE2E))
|
||||
{
|
||||
assert(false && "Input mesh is not PWN");
|
||||
std::cerr << "Input mesh is not PWN!" << std::endl;
|
||||
valid = false;
|
||||
}
|
||||
|
||||
const size_t num_faces = F.rows();
|
||||
typedef std::tuple<typename DerivedC::Scalar, bool, size_t> CellConnection;
|
||||
std::vector<std::set<CellConnection> > cell_adj;
|
||||
igl::copyleft::cgal::cell_adjacency(C, num_cells, cell_adj);
|
||||
#ifdef PROPAGATE_WINDING_NUMBER_TIMING
|
||||
log_time("cell_connectivity");
|
||||
#endif
|
||||
|
||||
auto save_cell = [&](const std::string& filename, size_t cell_id) -> void{
|
||||
std::vector<size_t> faces;
|
||||
for (size_t i=0; i<num_patches; i++) {
|
||||
if ((C.row(i).array() == cell_id).any()) {
|
||||
for (size_t j=0; j<num_faces; j++) {
|
||||
if ((size_t)P[j] == i) {
|
||||
faces.push_back(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Eigen::MatrixXi cell_faces(faces.size(), 3);
|
||||
for (size_t i=0; i<faces.size(); i++) {
|
||||
cell_faces.row(i) = F.row(faces[i]);
|
||||
}
|
||||
Eigen::MatrixXd vertices;
|
||||
assign(V,vertices);
|
||||
writePLY(filename, vertices, cell_faces);
|
||||
};
|
||||
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
// Check for odd cycle.
|
||||
Eigen::VectorXi cell_labels(num_cells);
|
||||
cell_labels.setZero();
|
||||
Eigen::VectorXi parents(num_cells);
|
||||
parents.setConstant(-1);
|
||||
auto trace_parents = [&](size_t idx) -> std::list<size_t> {
|
||||
std::list<size_t> path;
|
||||
path.push_back(idx);
|
||||
while ((size_t)parents[path.back()] != path.back()) {
|
||||
path.push_back(parents[path.back()]);
|
||||
}
|
||||
return path;
|
||||
};
|
||||
for (size_t i=0; i<num_cells; i++) {
|
||||
if (cell_labels[i] == 0) {
|
||||
cell_labels[i] = 1;
|
||||
std::queue<size_t> Q;
|
||||
Q.push(i);
|
||||
parents[i] = i;
|
||||
while (!Q.empty()) {
|
||||
size_t curr_idx = Q.front();
|
||||
Q.pop();
|
||||
int curr_label = cell_labels[curr_idx];
|
||||
for (const auto& neighbor : cell_adj[curr_idx]) {
|
||||
if (cell_labels[std::get<0>(neighbor)] == 0)
|
||||
{
|
||||
cell_labels[std::get<0>(neighbor)] = curr_label * -1;
|
||||
Q.push(std::get<0>(neighbor));
|
||||
parents[std::get<0>(neighbor)] = curr_idx;
|
||||
} else
|
||||
{
|
||||
if (cell_labels[std::get<0>(neighbor)] != curr_label * -1)
|
||||
{
|
||||
std::cerr << "Odd cell cycle detected!" << std::endl;
|
||||
auto path = trace_parents(curr_idx);
|
||||
path.reverse();
|
||||
auto path2 = trace_parents(std::get<0>(neighbor));
|
||||
path.insert(path.end(), path2.begin(), path2.end());
|
||||
for (auto cell_id : path)
|
||||
{
|
||||
std::cout << cell_id << " ";
|
||||
std::stringstream filename;
|
||||
filename << "cell_" << cell_id << ".ply";
|
||||
save_cell(filename.str(), cell_id);
|
||||
}
|
||||
std::cout << std::endl;
|
||||
valid = false;
|
||||
}
|
||||
// Do not fail when odd cycle is detected because the resulting
|
||||
// integer winding number field, although inconsistent, may still
|
||||
// be used if the problem region is local and embedded within a
|
||||
// valid volume.
|
||||
//assert(cell_labels[std::get<0>(neighbor)] == curr_label * -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef PROPAGATE_WINDING_NUMBER_TIMING
|
||||
log_time("odd_cycle_check");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t outer_facet;
|
||||
bool flipped;
|
||||
Eigen::VectorXi I = igl::LinSpaced<Eigen::VectorXi>(num_faces, 0, num_faces-1);
|
||||
igl::copyleft::cgal::outer_facet(V, F, I, outer_facet, flipped);
|
||||
#ifdef PROPAGATE_WINDING_NUMBER_TIMING
|
||||
log_time("outer_facet");
|
||||
#endif
|
||||
|
||||
const size_t outer_patch = P[outer_facet];
|
||||
const size_t infinity_cell = C(outer_patch, flipped?1:0);
|
||||
|
||||
Eigen::VectorXi patch_labels(num_patches);
|
||||
const int INVALID = std::numeric_limits<int>::max();
|
||||
patch_labels.setConstant(INVALID);
|
||||
for (size_t i=0; i<num_faces; i++) {
|
||||
if (patch_labels[P[i]] == INVALID) {
|
||||
patch_labels[P[i]] = labels[i];
|
||||
} else {
|
||||
assert(patch_labels[P[i]] == labels[i]);
|
||||
}
|
||||
}
|
||||
assert((patch_labels.array() != INVALID).all());
|
||||
const size_t num_labels = patch_labels.maxCoeff()+1;
|
||||
|
||||
Eigen::MatrixXi per_cell_W(num_cells, num_labels);
|
||||
per_cell_W.setConstant(INVALID);
|
||||
per_cell_W.row(infinity_cell).setZero();
|
||||
std::queue<size_t> Q;
|
||||
Q.push(infinity_cell);
|
||||
while (!Q.empty()) {
|
||||
size_t curr_cell = Q.front();
|
||||
Q.pop();
|
||||
for (const auto& neighbor : cell_adj[curr_cell]) {
|
||||
size_t neighbor_cell, patch_idx;
|
||||
bool direction;
|
||||
std::tie(neighbor_cell, direction, patch_idx) = neighbor;
|
||||
if ((per_cell_W.row(neighbor_cell).array() == INVALID).any()) {
|
||||
per_cell_W.row(neighbor_cell) = per_cell_W.row(curr_cell);
|
||||
for (size_t i=0; i<num_labels; i++) {
|
||||
int inc = (patch_labels[patch_idx] == (int)i) ?
|
||||
(direction ? -1:1) :0;
|
||||
per_cell_W(neighbor_cell, i) =
|
||||
per_cell_W(curr_cell, i) + inc;
|
||||
}
|
||||
Q.push(neighbor_cell);
|
||||
} else {
|
||||
#ifndef NDEBUG
|
||||
// Checking for winding number consistency.
|
||||
// This check would inevitably fail for meshes that contain open
|
||||
// boundary or non-orientable. However, the inconsistent winding number
|
||||
// field would still be useful in some cases such as when problem region
|
||||
// is local and embedded within the volume. This, unfortunately, is the
|
||||
// best we can do because the problem of computing integer winding
|
||||
// number is ill-defined for open and non-orientable surfaces.
|
||||
for (size_t i=0; i<num_labels; i++) {
|
||||
if ((int)i == patch_labels[patch_idx]) {
|
||||
int inc = direction ? -1:1;
|
||||
//assert(per_cell_W(neighbor_cell, i) ==
|
||||
// per_cell_W(curr_cell, i) + inc);
|
||||
} else {
|
||||
//assert(per_cell_W(neighbor_cell, i) ==
|
||||
// per_cell_W(curr_cell, i));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef PROPAGATE_WINDING_NUMBER_TIMING
|
||||
log_time("propagate_winding_number");
|
||||
#endif
|
||||
|
||||
W.resize(num_faces, num_labels*2);
|
||||
for (size_t i=0; i<num_faces; i++)
|
||||
{
|
||||
const size_t patch = P[i];
|
||||
const size_t positive_cell = C(patch, 0);
|
||||
const size_t negative_cell = C(patch, 1);
|
||||
for (size_t j=0; j<num_labels; j++) {
|
||||
W(i,j*2 ) = per_cell_W(positive_cell, j);
|
||||
W(i,j*2+1) = per_cell_W(negative_cell, j);
|
||||
}
|
||||
}
|
||||
#ifdef PROPAGATE_WINDING_NUMBER_TIMING
|
||||
log_time("store_result");
|
||||
#endif
|
||||
return valid;
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template bool igl::copyleft::cgal::propagate_winding_numbers<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, unsigned long, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, unsigned long, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
// generated by autoexplicit.sh
|
||||
template bool igl::copyleft::cgal::propagate_winding_numbers<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, unsigned long, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, unsigned long, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
template bool igl::copyleft::cgal::propagate_winding_numbers<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
#ifdef WIN32
|
||||
template bool igl::copyleft::cgal::propagate_winding_numbers<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, unsigned __int64, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, unsigned __int64, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &);
|
||||
template bool igl::copyleft::cgal::propagate_winding_numbers<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, unsigned __int64, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, unsigned __int64, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &);
|
||||
#endif
|
||||
#endif
|
||||
103
src/libigl/igl/copyleft/cgal/propagate_winding_numbers.h
Normal file
103
src/libigl/igl/copyleft/cgal/propagate_winding_numbers.h
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
#ifndef IGL_COPYLEFT_CGAL_PROPAGATE_WINDING_NUMBERS_H
|
||||
#define IGL_COPYLEFT_CGAL_PROPAGATE_WINDING_NUMBERS_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
|
||||
// The following methods compute the winding number on each side of each facet
|
||||
// or patch of a 3D mesh. The input mesh is valid if it splits the ambient
|
||||
// space, R^3, into subspaces with constant integer winding numbers. That is
|
||||
// the input mesh should be closed and for each directed edge the number of
|
||||
// clockwise facing facets should equal the number of counterclockwise facing
|
||||
// facets.
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// TODO: This shouldn't need to be in igl::copyleft::cgal, it should
|
||||
// instead take as input an index of the ambient cell and the winding
|
||||
// number vector there.
|
||||
//
|
||||
// Compute winding number on each side of the face. The input mesh
|
||||
// could contain multiple connected components. The input mesh must
|
||||
// represent the boundary of a valid 3D volume, which means it is
|
||||
// closed, consistently oriented and induces integer winding numbers.
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions.
|
||||
// F #F by 3 list of triangle indices into V.
|
||||
// labels #F list of facet labels ranging from 0 to k-1.
|
||||
// Output:
|
||||
// W #F by k*2 list of winding numbers. ``W(i,j*2)`` is the winding
|
||||
// number on the positive side of facet ``i`` with respect to the
|
||||
// facets labeled ``j``. Similarly, ``W(i,j*2+1)`` is the winding
|
||||
// number on the negative side of facet ``i`` with respect to the
|
||||
// facets labeled ``j``.
|
||||
// Returns true iff the input induces a piecewise-constant winding number
|
||||
// field.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedL,
|
||||
typename DerivedW>
|
||||
IGL_INLINE bool propagate_winding_numbers(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DerivedL>& labels,
|
||||
Eigen::PlainObjectBase<DerivedW>& W);
|
||||
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions.
|
||||
// F #F by 3 list of triangle indices into V.
|
||||
// uE #uE by 2 list of vertex_indices, represents undirected edges.
|
||||
// uE2E #uE list of lists that maps uE to E. (a one-to-many map)
|
||||
// num_patches number of patches
|
||||
// P #F list of patch ids.
|
||||
// num_cells number of cells
|
||||
// C #P by 2 list of cell ids on each side of each patch.
|
||||
// labels #F list of facet labels ranging from 0 to k-1.
|
||||
// Output:
|
||||
// W #F by k*2 list of winding numbers. ``W(i,j*2)`` is the winding
|
||||
// number on the positive side of facet ``i`` with respect to the
|
||||
// facets labeled ``j``. Similarly, ``W(i,j*2+1)`` is the winding
|
||||
// number on the negative side of facet ``i`` with respect to the
|
||||
// facets labeled ``j``.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DeriveduE,
|
||||
typename uE2EType,
|
||||
typename DerivedP,
|
||||
typename DerivedC,
|
||||
typename DerivedL,
|
||||
typename DerivedW>
|
||||
IGL_INLINE bool propagate_winding_numbers(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
||||
const std::vector<std::vector<uE2EType> >& uE2E,
|
||||
const size_t num_patches,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const size_t num_cells,
|
||||
const Eigen::PlainObjectBase<DerivedC>& C,
|
||||
const Eigen::PlainObjectBase<DerivedL>& labels,
|
||||
Eigen::PlainObjectBase<DerivedW>& W);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "propagate_winding_numbers.cpp"
|
||||
#endif
|
||||
#endif
|
||||
26
src/libigl/igl/copyleft/cgal/read_triangle_mesh.cpp
Normal file
26
src/libigl/igl/copyleft/cgal/read_triangle_mesh.cpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "read_triangle_mesh.h"
|
||||
#include "assign.h"
|
||||
#include "../../read_triangle_mesh.h"
|
||||
|
||||
template <typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE bool igl::copyleft::cgal::read_triangle_mesh(
|
||||
const std::string str,
|
||||
Eigen::PlainObjectBase<DerivedV>& V,
|
||||
Eigen::PlainObjectBase<DerivedF>& F)
|
||||
{
|
||||
Eigen::MatrixXd Vd;
|
||||
bool ret = igl::read_triangle_mesh(str,Vd,F);
|
||||
if(ret)
|
||||
{
|
||||
assign(Vd,V);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
42
src/libigl/igl/copyleft/cgal/read_triangle_mesh.h
Normal file
42
src/libigl/igl/copyleft/cgal/read_triangle_mesh.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_COPYLEFT_CGAL_READ_TRIANGLE_MESH_H
|
||||
#define IGL_COPYLEFT_CGAL_READ_TRIANGLE_MESH_H
|
||||
#include "../../igl_inline.h"
|
||||
|
||||
#include <Eigen/Core>
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Simple wrapper, reads floating point precision but assigns to
|
||||
// DerivedV::Scalar which may be a CGAL type
|
||||
//
|
||||
// Inputs:
|
||||
// str path to file
|
||||
// Outputs:
|
||||
// V eigen double matrix #V by 3
|
||||
// F eigen int matrix #F by 3
|
||||
// Returns true iff success
|
||||
template <typename DerivedV, typename DerivedF>
|
||||
IGL_INLINE bool read_triangle_mesh(
|
||||
const std::string str,
|
||||
Eigen::PlainObjectBase<DerivedV>& V,
|
||||
Eigen::PlainObjectBase<DerivedF>& F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "read_triangle_mesh.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
117
src/libigl/igl/copyleft/cgal/relabel_small_immersed_cells.cpp
Normal file
117
src/libigl/igl/copyleft/cgal/relabel_small_immersed_cells.cpp
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
|
||||
#include "relabel_small_immersed_cells.h"
|
||||
#include "../../centroid.h"
|
||||
#include "assign.h"
|
||||
#include "cell_adjacency.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename DerivedC,
|
||||
typename FT,
|
||||
typename DerivedW>
|
||||
IGL_INLINE void igl::copyleft::cgal::relabel_small_immersed_cells(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const size_t num_patches,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const size_t num_cells,
|
||||
const Eigen::PlainObjectBase<DerivedC>& C,
|
||||
const FT vol_threashold,
|
||||
Eigen::PlainObjectBase<DerivedW>& W)
|
||||
{
|
||||
const size_t num_vertices = V.rows();
|
||||
const size_t num_faces = F.rows();
|
||||
typedef std::tuple<typename DerivedC::Scalar, bool, size_t> CellConnection;
|
||||
std::vector<std::set<CellConnection> > cell_adj;
|
||||
igl::copyleft::cgal::cell_adjacency(C, num_cells, cell_adj);
|
||||
|
||||
Eigen::MatrixXd VV;
|
||||
assign(V,VV);
|
||||
|
||||
auto compute_cell_volume = [&](size_t cell_id) {
|
||||
std::vector<short> is_involved(num_patches, 0);
|
||||
for (size_t i=0; i<num_patches; i++) {
|
||||
if (C(i,0) == cell_id) {
|
||||
// cell is on positive side of patch i.
|
||||
is_involved[i] = 1;
|
||||
}
|
||||
if (C(i,1) == cell_id) {
|
||||
// cell is on negative side of patch i.
|
||||
is_involved[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<size_t> involved_positive_faces;
|
||||
std::vector<size_t> involved_negative_faces;
|
||||
for (size_t i=0; i<num_faces; i++) {
|
||||
switch (is_involved[P[i]]) {
|
||||
case 1:
|
||||
involved_negative_faces.push_back(i);
|
||||
break;
|
||||
case -1:
|
||||
involved_positive_faces.push_back(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const size_t num_positive_faces = involved_positive_faces.size();
|
||||
const size_t num_negative_faces = involved_negative_faces.size();
|
||||
DerivedF selected_faces(num_positive_faces + num_negative_faces, 3);
|
||||
for (size_t i=0; i<num_positive_faces; i++) {
|
||||
selected_faces.row(i) = F.row(involved_positive_faces[i]);
|
||||
}
|
||||
for (size_t i=0; i<num_negative_faces; i++) {
|
||||
selected_faces.row(num_positive_faces+i) =
|
||||
F.row(involved_negative_faces[i]).reverse();
|
||||
}
|
||||
|
||||
Eigen::VectorXd c(3);
|
||||
double vol;
|
||||
igl::centroid(VV, selected_faces, c, vol);
|
||||
return vol;
|
||||
};
|
||||
|
||||
std::vector<typename DerivedV::Scalar> cell_volumes(num_cells);
|
||||
for (size_t i=0; i<num_cells; i++) {
|
||||
cell_volumes[i] = compute_cell_volume(i);
|
||||
}
|
||||
|
||||
std::vector<typename DerivedW::Scalar> cell_values(num_cells);
|
||||
for (size_t i=0; i<num_faces; i++) {
|
||||
cell_values[C(P[i], 0)] = W(i, 0);
|
||||
cell_values[C(P[i], 1)] = W(i, 1);
|
||||
}
|
||||
|
||||
for (size_t i=1; i<num_cells; i++) {
|
||||
std::cout << cell_volumes[i] << std::endl;
|
||||
if (cell_volumes[i] >= vol_threashold) continue;
|
||||
std::set<typename DerivedW::Scalar> neighbor_values;
|
||||
const auto neighbors = cell_adj[i];
|
||||
for (const auto& entry : neighbors) {
|
||||
const auto& j = std::get<0>(entry);
|
||||
neighbor_values.insert(cell_values[j]);
|
||||
}
|
||||
// If cell i is immersed, assign its value to be the immersed value.
|
||||
if (neighbor_values.size() == 1) {
|
||||
cell_values[i] = *neighbor_values.begin();
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i=0; i<num_faces; i++) {
|
||||
W(i,0) = cell_values[C(P[i], 0)];
|
||||
W(i,1) = cell_values[C(P[i], 1)];
|
||||
}
|
||||
}
|
||||
|
||||
59
src/libigl/igl/copyleft/cgal/relabel_small_immersed_cells.h
Normal file
59
src/libigl/igl/copyleft/cgal/relabel_small_immersed_cells.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2016 Qingnan Zhou <qnzhou@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
#ifndef IGL_RELABEL_SMALL_IMMERSED_CELLS
|
||||
#define IGL_RELABEL_SMALL_IMMERSED_CELLS
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace copyleft
|
||||
{
|
||||
namespace cgal
|
||||
{
|
||||
// Inputs:
|
||||
// V #V by 3 list of vertex positions.
|
||||
// F #F by 3 list of triangle indices into V.
|
||||
// num_patches number of patches
|
||||
// P #F list of patch ids.
|
||||
// num_cells number of cells
|
||||
// C #P by 2 list of cell ids on each side of each patch.
|
||||
// vol_threshold Volume threshold, cells smaller than this
|
||||
// and is completely immersed will be relabeled.
|
||||
//
|
||||
// In/Output:
|
||||
// W #F by 2 cell labels. W(i,0) is the label on the positive side of
|
||||
// face i, W(i,1) is the label on the negative side of face i. W
|
||||
// will be modified in place by this method.
|
||||
template<
|
||||
typename DerivedV,
|
||||
typename DerivedF,
|
||||
typename DerivedP,
|
||||
typename DerivedC,
|
||||
typename FT,
|
||||
typename DerivedW>
|
||||
IGL_INLINE void relabel_small_immersed_cells(
|
||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||
const size_t num_patches,
|
||||
const Eigen::PlainObjectBase<DerivedP>& P,
|
||||
const size_t num_cells,
|
||||
const Eigen::PlainObjectBase<DerivedC>& C,
|
||||
const FT vol_threashold,
|
||||
Eigen::PlainObjectBase<DerivedW>& W);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "relabel_small_immersed_cells.cpp"
|
||||
#endif
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue