Update eigen to v5.0.1 and libigl to v2.6.0. (#11311)

* Update eigen from v3.3.7 to v5.0.1.

This updates eigen from v3.3.7 released on  December 11, 2018-12-11 to v5.0.1
released on 2025-11-11. There have be a large number of bug-fixes,
optimizations, and improvements between these releases. See the details at;

https://gitlab.com/libeigen/eigen/-/releases

It retains the previous custom minimal `CMakeLists.txt`, and adds a
README-OrcaSlicer.md that explains what version and parts of the upstream
eigen release have been included, and where the full release can be found.

* Update libigl from v2.0.0 (or older) to v2.6.0.

This updates libigl from what was probably v2.0.0 released on 2018-10-16 to
v2.6.0 released on 2025-05-15. It's possible the old version was even older
than that but there is no version indicators in the code and I ran out of
patience identifying missing changes and only went back as far as v2.0.0.

There have been a large number of bug-fixes, optimizations, and improvements
between these versions. See the following for details;

https://github.com/libigl/libigl/releases

I retained the minimal custom `CMakeLists.txt`, added `README.md` from the
libigl distribution which identifies the version, and added a
README-OrcaSlicer.md that details the version and parts that have been
included.

* Update libslic3r for libigl v2.6.0 changes.

This updates libslic3r for all changes moving to eigen v5.0.1 and libigl
v2.6.0. Despite the large number of updates to both dependencies, no changes
were required for the eigen update, and only one change was required for the
libigl update.

For libigl, `igl::Hit` was changed to a template taking the Scalar type to
use. Previously it was hard-coded to `float`, so to minimize possible impact
I've updated all places it is used from `igl::Hit` to `igl::Hit<float>`.

* Add compiler option `-DNOMINMAX` for libigl with MSVC.

MSVC by default defines `min(()` and `max()` macros that break
`std::numeric_limits<>::max()`. The upstream cmake that we don't include
adds `-DNOMINMAX` for the libigl module when compiling with MSVC, so we need
to add the same thing here.

* Fix src/libslic3r/TriangleMeshDeal.cpp for the unmodified upstream libigl.

This fixes `TriangleMeshDeal.cpp` to work with the unmodified upstream
libigl v2.6.0. loop.{h,cpp} implementation.

This file and feature was added in PR "BBS Port: Mesh Subdivision" (#12150)
which included changes to `loop.{h,cpp}` in the old version of libigl. This PR
avoids modifying the included dependencies, and uses the updated upstream
versions of those files without any modifications, which requires fixing
TriangleMeshDeal.cpp to work with them.

In particular, the modifications made to `loop.{h,cpp}` included changing the
return type from void to bool, adding additional validation checking of the
input meshes, and returning false if they failed validation. These added
checks looked unnecessary and would only have caught problems if the input
mesh was very corrupt.

To make `TriangleMeshDeal.cpp` work without this built-in checking
functionality, I removed checking/handling of any `false` return value.

There was also a hell of a lot of redundant copying and casting back and forth
between float and double, so I cleaned that up. The input and output meshs use
floats for the vertexes, and there would be no accuracy benefits from casting
to and from doubles for the simple weighted average operations done by
igl::loop(). So this just uses `Eigen:Map` to use the original input mesh
vertex data directly without requiring any copy or casting.

* Move eigen from included `deps_src` to externaly fetched `deps`.

This copys what PrusaSlicer did and moved it from an included dependency under
`deps_src` to an externaly fetched dependency under `deps`. This requires
updating some `CMakeList.txt` configs and removing the old and obsolete
`cmake/modules/FindEigen3.cmake`. The details of when this was done in
PrusaSlicer and the followup fixes are at;

* 21116995d7
* https://github.com/prusa3d/PrusaSlicer/issues/13608
* https://github.com/prusa3d/PrusaSlicer/pull/13609
* e3c277b9ee

For some reason I don't fully understand this also required fixing
`src/slic3r/GUI/GUI_App.cpp` by adding `#include <boost/nowide/cstdio.hpp>` to
fix an `error: ‘remove’ is not a member of ‘boost::nowide'`. The main thing I
don't understand is how it worked before. Note that this include is in the
PrusaSlicer version of this file, but it also significantly deviates from what
is currently in OrcaSlicer in many other ways.

* Whups... I missed adding the deps/Eigen/Eigen.cmake file...

* Tidy some whitespace indenting in CMakeLists.txt.

* Ugh... tabs indenting needing fixes.

* Change the include order of deps/Eigen.

It turns out that although Boost includes some references to Eigen, Eigen also
includes some references to Boost for supporting some of it's additional
numeric types.

I don't think it matters much since we are not using these features, but I
think technically its more correct to say Eigen depends on Boost than the
other way around, so I've re-ordered them.

* Add source for Eigen 5.0.1 download to flatpak yml config.

* Add explicit `DEPENDS dep_Boost to deps/Eigen.

I missed this before. This ensures we don't rely on include orders to make
sure Boost is installed before we configure Eigen.

* Add `DEPENDS dep_Boost dep_GMP dep_MPFR` to deps/Eigen.

It turns out Eigen can also use GMP and MPFR for multi-precision and
multi-precision-rounded numeric types if they are available.

Again, I don't think we are using these so it doesn't really matter, but it is
technically correct and ensures they are there if we ever do need them.

* Fix deps DEPENDENCY ordering for GMP, MPFR, Eigen, and CGAL.

I think this is finally correct. Apparently CGAL also optionally depends on
Eigen, so the correct dependency order from lowest to highest is GMP, MPFR, Eigen, and CGAL.

---------

Co-authored-by: Donovan Baarda <dbaarda@google.com>
Co-authored-by: Noisyfox <timemanager.rick@gmail.com>
This commit is contained in:
Donovan Baarda
2026-05-12 17:09:13 +10:00
committed by GitHub
parent 797ee70b0b
commit dc5897d7b5
1573 changed files with 63323 additions and 161343 deletions

View File

@@ -15,3 +15,8 @@ else()
INTERFACE
${CMAKE_CURRENT_SOURCE_DIR})
endif()
if(MSVC)
# disable min() and max() macros that break std::numeric_limits<>::max()
target_compile_definitions(libigl INTERFACE -DNOMINMAX)
endif()

View File

@@ -0,0 +1,16 @@
# libigl in OrcaSlicer.
> [!NOTE]
> This is not the complete libigl distribution! Only the files needed for
> compiling libigl into OrcaSlicer are included in the OrcaSlicer source
> distribution. The full libigl distribution can be found at;
>
> https://github.com/libigl/libigl
This directory contains parts of the libigl v2.6.0 (40e7900) source
distribution together with a minimal custom `CMakeLists.txt` file. In
particular only the following files from the full libigl distribution are
included;
* README.md
* include/igl/* -> igl/*

13
deps_src/libigl/README.md Normal file
View File

@@ -0,0 +1,13 @@
# libigl - A simple C++ geometry processing library
[![](https://github.com/libigl/libigl/workflows/Build/badge.svg?event=push)](https://github.com/libigl/libigl/actions?query=workflow%3ABuild+branch%3Amain+event%3Apush)
[![](https://anaconda.org/conda-forge/igl/badges/installer/conda.svg)](https://anaconda.org/conda-forge/igl)
![](https://libigl.github.io/libigl-teaser.png)
Documentation, tutorial, and instructions at <https://libigl.github.io>.
| 🆕 Doxygen Documentation |
|:---|
| The latest version of libigl (v2.5.0) introduces [doxygen generated detailed documentation](https://libigl.github.io/dox/index.html) |

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -9,27 +9,24 @@
#define IGL_ARAPENERGYTYPE_H
namespace igl
{
// ARAP_ENERGY_TYPE_SPOKES "As-rigid-as-possible Surface Modeling" by [Sorkine and
// Alexa 2007], rotations defined at vertices affecting incident edges,
// default
// ARAP_ENERGY_TYPE_SPOKES-AND-RIMS Adapted version of "As-rigid-as-possible Surface
// Modeling" by [Sorkine and Alexa 2007] presented in section 4.2 of or
// "A simple geometric model for elastic deformation" by [Chao et al.
// 2010], rotations defined at vertices affecting incident edges and
// opposite edges
// ARAP_ENERGY_TYPE_ELEMENTS "A local-global approach to mesh parameterization" by
// [Liu et al. 2010] or "A simple geometric model for elastic
// deformation" by [Chao et al. 2010], rotations defined at elements
// (triangles or tets)
// ARAP_ENERGY_TYPE_DEFAULT Choose one automatically: spokes and rims
// for surfaces, elements for planar meshes and tets (not fully
// supported)
/// Enum for choosing ARAP energy type
enum ARAPEnergyType
{
/// "As-rigid-as-possible Surface Modeling" by [Sorkine and Alexa 2007],
/// rotations defined at vertices affecting incident edges, default
ARAP_ENERGY_TYPE_SPOKES = 0,
/// Adapted version of "As-rigid-as-possible Surface Modeling" by [Sorkine
/// and Alexa 2007] presented in section 4.2 of or "A simple geometric model
/// for elastic deformation" by [Chao et al.\ 2010], rotations defined at
/// vertices affecting incident edges and opposite edges
ARAP_ENERGY_TYPE_SPOKES_AND_RIMS = 1,
/// "A local-global approach to mesh parameterization" by [Liu et al.\ 2010]
/// or "A simple geometric model for elastic deformation" by [Chao et al.\ 2010], rotations defined at elements (triangles or tets)
ARAP_ENERGY_TYPE_ELEMENTS = 2,
/// Choose one automatically: spokes and rims for surfaces, elements for
/// planar meshes and tets (not fully supported)
ARAP_ENERGY_TYPE_DEFAULT = 3,
/// Total number of types
NUM_ARAP_ENERGY_TYPES = 4
};
}

View File

@@ -6,6 +6,7 @@
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "AtA_cached.h"
#include "IGL_ASSERT.h"
#include <iostream>
#include <vector>
@@ -34,12 +35,12 @@ IGL_INLINE void igl::AtA_cached_precompute(
int col = k;
int row = *(A.innerIndexPtr()+l);
int value_index = l;
assert(col < A.cols());
assert(col >= 0);
assert(row < A.rows());
assert(row >= 0);
assert(value_index >= 0);
assert(value_index < A.nonZeros());
IGL_ASSERT(col < A.cols());
IGL_ASSERT(col >= 0);
IGL_ASSERT(row < A.rows());
IGL_ASSERT(row >= 0);
IGL_ASSERT(value_index >= 0);
IGL_ASSERT(value_index < A.nonZeros());
Col_RowPtr[col].push_back(row);
Col_IndexPtr[col].push_back(value_index);
@@ -74,12 +75,12 @@ IGL_INLINE void igl::AtA_cached_precompute(
int col = k;
int row = *(AtA.innerIndexPtr()+l);
int value_index = l;
assert(col < AtA.cols());
assert(col >= 0);
assert(row < AtA.rows());
assert(row >= 0);
assert(value_index >= 0);
assert(value_index < AtA.nonZeros());
IGL_ASSERT(col < AtA.cols());
IGL_ASSERT(col >= 0);
IGL_ASSERT(row < AtA.rows());
IGL_ASSERT(row >= 0);
IGL_ASSERT(value_index >= 0);
IGL_ASSERT(value_index < AtA.nonZeros());
data.I_outer.push_back(data.I_row.size());

View File

@@ -13,40 +13,47 @@
#include <Eigen/Sparse>
namespace igl
{
/// Hold precomputed data for AtA_cached
struct AtA_cached_data
{
// Weights
/// Weights (diagonal of W)
Eigen::VectorXd W;
// Flatten composition rules
/// @private
std::vector<int> I_row;
/// @private
std::vector<int> I_col;
/// @private
std::vector<int> I_w;
// For each entry of AtA, points to the beginning
// of the composition rules
/// @private
std::vector<int> I_outer;
};
// Computes At * W * A, where A is sparse and W is diagonal. Divides the
// construction in two phases, one
// for fixing the sparsity pattern, and one to populate it with values. Compared to
// evaluating it directly, this version is slower for the first time (since it requires a
// precomputation), but faster to the subsequent evaluations.
//
// Input:
// A m x n sparse matrix
// data stores the precomputed sparsity pattern, data.W contains the optional diagonal weights (stored as a dense vector). If W is not provided, it is replaced by the identity.
// Outputs:
// AtA m by m matrix computed as AtA * W * A
//
// Example:
// AtA_data = igl::AtA_cached_data();
// AtA_data.W = W;
// if (s.AtA.rows() == 0)
// igl::AtA_cached_precompute(s.A,s.AtA_data,s.AtA);
// else
// igl::AtA_cached(s.A,s.AtA_data,s.AtA);
/// Computes At * W * A, where A is sparse and W is diagonal.
///
/// Divides the construction in two phases, one for fixing the sparsity
/// pattern, and one to populate it with values. Compared to evaluating it
/// directly, this version is slower for the first time (since it requires a
/// precomputation), but faster to the subsequent evaluations.
///
/// @param[in] A m x n sparse matrix
/// @param[in,out] data stores the precomputed sparsity pattern, data.W contains the optional diagonal weights (stored as a dense vector). If W is not provided, it is replaced by the identity.
/// @param[out] AtA m by m matrix computed as AtA * W * A
///
/// #### Example:
///
/// \code{cpp}
/// AtA_data = igl::AtA_cached_data();
/// AtA_data.W = W;
/// if (s.AtA.rows() == 0)
/// igl::AtA_cached_precompute(s.A,s.AtA_data,s.AtA);
/// else
/// igl::AtA_cached(s.A,s.AtA_data,s.AtA);
/// \endcode
template <typename Scalar>
IGL_INLINE void AtA_cached_precompute(
const Eigen::SparseMatrix<Scalar>& A,
@@ -54,6 +61,11 @@ namespace igl
Eigen::SparseMatrix<Scalar>& AtA
);
/// Computes At * W * A, where A is sparse and W is diagonal precomputed into data.
///
/// @param[in] A m x n sparse matrix
/// @param[in] data stores the precomputed sparsity pattern, data.W contains the optional diagonal weights (stored as a dense vector). If W is not provided, it is replaced by the identity.
/// @param[out] AtA m by m matrix computed as AtA * W * A
template <typename Scalar>
IGL_INLINE void AtA_cached(
const Eigen::SparseMatrix<Scalar>& A,

View File

@@ -0,0 +1,19 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2025 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_COLLAPSE_EDGE_NULL_H
#define IGL_COLLAPSE_EDGE_NULL_H
namespace igl
{
#ifndef IGL_COLLAPSE_EDGE_NULL
/// Special value for indicating a null vertex index as the result of a
/// collapsed edge.
#define IGL_COLLAPSE_EDGE_NULL 0
#endif
}
#endif

View File

@@ -7,12 +7,23 @@
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_C_STR_H
#define IGL_C_STR_H
// http://stackoverflow.com/a/2433143/148668
// Suppose you have a function:
// void func(const char * c);
// Then you can write:
// func(C_STR("foo"<<1<<"bar"));
#include <sstream>
#include <string>
/// Convert a stream of things to a const char *.
///
/// Suppose you have a function:
/// \code{cpp}
/// void func(const char * c);
/// \endcode
/// Then you can write:
/// \code{cpp}
/// func(C_STR("foo"<<1<<"bar"));
/// \endcode
/// which is equivalent to:
/// \code{cpp}
/// func("foo1bar");
/// \endcode
///
// http://stackoverflow.com/a/2433143/148668
#define C_STR(X) static_cast<std::ostringstream&>(std::ostringstream().flush() << X).str().c_str()
#endif

View File

@@ -1,359 +0,0 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_CAMERA_H
#define IGL_CAMERA_H
// you're idiot, M$!
#if defined(_WIN32)
#undef far
#undef near
#endif
#include <Eigen/Geometry>
#include <Eigen/Core>
#include <PI.h>
#define IGL_CAMERA_MIN_ANGLE 5.0
namespace igl
{
// A simple camera class. The camera stores projection parameters (field of
// view angle, aspect ratio, near and far clips) as well as a rigid
// transformation *of the camera as if it were also a scene object*. Thus, the
// **inverse** of this rigid transformation is the modelview transformation.
class Camera
{
public:
// On windows you might need: -fno-delayed-template-parsing
//static constexpr double IGL_CAMERA_MIN_ANGLE = 5.;
// m_angle Field of view angle in degrees {45}
// m_aspect Aspect ratio {1}
// m_near near clipping plane {1e-2}
// m_far far clipping plane {100}
// m_at_dist distance of looking at point {1}
// m_orthographic whether to use othrographic projection {false}
// m_rotation_conj Conjugate of rotation part of rigid transformation of
// camera {identity}. Note: we purposefully store the conjugate because
// this is what TW_TYPE_QUAT4D is expecting.
// m_translation Translation part of rigid transformation of camera
// {(0,0,1)}
double m_angle, m_aspect, m_near, m_far, m_at_dist;
bool m_orthographic;
Eigen::Quaterniond m_rotation_conj;
Eigen::Vector3d m_translation;
public:
inline Camera();
inline virtual ~Camera(){}
// Return projection matrix that takes relative camera coordinates and
// transforms it to viewport coordinates
//
// Note:
//
// if(m_angle > 0)
// {
// gluPerspective(m_angle,m_aspect,m_near,m_at_dist+m_far);
// }else
// {
// gluOrtho(-0.5*aspect,0.5*aspect,-0.5,0.5,m_at_dist+m_near,m_far);
// }
//
// Is equivalent to
//
// glMultMatrixd(projection().data());
//
inline Eigen::Matrix4d projection() const;
// Return an Affine transformation (rigid actually) that
// takes relative coordinates and tramsforms them into world 3d
// coordinates: moves the camera into the scene.
inline Eigen::Affine3d affine() const;
// Return an Affine transformation (rigid actually) that puts the takes a
// world 3d coordinate and transforms it into the relative camera
// coordinates: moves the scene in front of the camera.
//
// Note:
//
// gluLookAt(
// eye()(0), eye()(1), eye()(2),
// at()(0), at()(1), at()(2),
// up()(0), up()(1), up()(2));
//
// Is equivalent to
//
// glMultMatrixd(camera.inverse().matrix().data());
//
// See also: affine, eye, at, up
inline Eigen::Affine3d inverse() const;
// Returns world coordinates position of center or "eye" of camera.
inline Eigen::Vector3d eye() const;
// Returns world coordinate position of a point "eye" is looking at.
inline Eigen::Vector3d at() const;
// Returns world coordinate unit vector of "up" vector
inline Eigen::Vector3d up() const;
// Return top right corner of unit plane in relative coordinates, that is
// (w/2,h/2,1)
inline Eigen::Vector3d unit_plane() const;
// Move dv in the relative coordinate frame of the camera (move the FPS)
//
// Inputs:
// dv (x,y,z) displacement vector
//
inline void dolly(const Eigen::Vector3d & dv);
// "Scale zoom": Move `eye`, but leave `at`
//
// Input:
// s amount to scale distance to at
inline void push_away(const double s);
// Aka "Hitchcock", "Vertigo", "Spielberg" or "Trombone" zoom:
// simultaneously dolly while changing angle so that `at` not only stays
// put in relative coordinates but also projected coordinates. That is
//
// Inputs:
// da change in angle in degrees
inline void dolly_zoom(const double da);
// Turn around eye so that rotation is now q
//
// Inputs:
// q new rotation as quaternion
inline void turn_eye(const Eigen::Quaterniond & q);
// Orbit around at so that rotation is now q
//
// Inputs:
// q new rotation as quaternion
inline void orbit(const Eigen::Quaterniond & q);
// Rotate and translate so that camera is situated at "eye" looking at "at"
// with "up" pointing up.
//
// Inputs:
// eye (x,y,z) coordinates of eye position
// at (x,y,z) coordinates of at position
// up (x,y,z) coordinates of up vector
inline void look_at(
const Eigen::Vector3d & eye,
const Eigen::Vector3d & at,
const Eigen::Vector3d & up);
// Needed any time Eigen Structures are used as class members
// http://eigen.tuxfamily.org/dox-devel/group__TopicStructHavingEigenMembers.html
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};
}
// Implementation
#include "PI.h"
#include "EPS.h"
#include <cmath>
#include <iostream>
#include <cassert>
inline igl::Camera::Camera():
m_angle(45.0),m_aspect(1),m_near(1e-2),m_far(100),m_at_dist(1),
m_orthographic(false),
m_rotation_conj(1,0,0,0),
m_translation(0,0,1)
{
}
inline Eigen::Matrix4d igl::Camera::projection() const
{
Eigen::Matrix4d P;
using namespace std;
const double far = m_at_dist + m_far;
const double near = m_near;
// http://stackoverflow.com/a/3738696/148668
if(m_orthographic)
{
const double f = 0.5;
const double left = -f*m_aspect;
const double right = f*m_aspect;
const double bottom = -f;
const double top = f;
const double tx = (right+left)/(right-left);
const double ty = (top+bottom)/(top-bottom);
const double tz = (far+near)/(far-near);
const double z_fix = 0.5 /m_at_dist / tan(m_angle*0.5 * (igl::PI/180.) );
P<<
z_fix*2./(right-left), 0, 0, -tx,
0, z_fix*2./(top-bottom), 0, -ty,
0, 0, -z_fix*2./(far-near), -tz,
0, 0, 0, 1;
}else
{
const double yScale = tan(PI*0.5 - 0.5*m_angle*PI/180.);
// http://stackoverflow.com/a/14975139/148668
const double xScale = yScale/m_aspect;
P<<
xScale, 0, 0, 0,
0, yScale, 0, 0,
0, 0, -(far+near)/(far-near), -1,
0, 0, -2.*near*far/(far-near), 0;
P = P.transpose().eval();
}
return P;
}
inline Eigen::Affine3d igl::Camera::affine() const
{
using namespace Eigen;
Affine3d t = Affine3d::Identity();
t.rotate(m_rotation_conj.conjugate());
t.translate(m_translation);
return t;
}
inline Eigen::Affine3d igl::Camera::inverse() const
{
using namespace Eigen;
Affine3d t = Affine3d::Identity();
t.translate(-m_translation);
t.rotate(m_rotation_conj);
return t;
}
inline Eigen::Vector3d igl::Camera::eye() const
{
using namespace Eigen;
return affine() * Vector3d(0,0,0);
}
inline Eigen::Vector3d igl::Camera::at() const
{
using namespace Eigen;
return affine() * (Vector3d(0,0,-1)*m_at_dist);
}
inline Eigen::Vector3d igl::Camera::up() const
{
using namespace Eigen;
Affine3d t = Affine3d::Identity();
t.rotate(m_rotation_conj.conjugate());
return t * Vector3d(0,1,0);
}
inline Eigen::Vector3d igl::Camera::unit_plane() const
{
// Distance of center pixel to eye
const double d = 1.0;
const double a = m_aspect;
const double theta = m_angle*PI/180.;
const double w =
2.*sqrt(-d*d/(a*a*pow(tan(0.5*theta),2.)-1.))*a*tan(0.5*theta);
const double h = w/a;
return Eigen::Vector3d(w*0.5,h*0.5,-d);
}
inline void igl::Camera::dolly(const Eigen::Vector3d & dv)
{
m_translation += dv;
}
inline void igl::Camera::push_away(const double s)
{
using namespace Eigen;
#ifndef NDEBUG
Vector3d old_at = at();
#endif
const double old_at_dist = m_at_dist;
m_at_dist = old_at_dist * s;
dolly(Vector3d(0,0,1)*(m_at_dist - old_at_dist));
assert((old_at-at()).squaredNorm() < DOUBLE_EPS);
}
inline void igl::Camera::dolly_zoom(const double da)
{
using namespace std;
using namespace Eigen;
#ifndef NDEBUG
Vector3d old_at = at();
#endif
const double old_angle = m_angle;
if(old_angle + da < IGL_CAMERA_MIN_ANGLE)
{
m_orthographic = true;
}else if(old_angle + da > IGL_CAMERA_MIN_ANGLE)
{
m_orthographic = false;
}
if(!m_orthographic)
{
m_angle += da;
m_angle = min(89.,max(IGL_CAMERA_MIN_ANGLE,m_angle));
// change in distance
const double s =
(2.*tan(old_angle/2./180.*igl::PI)) /
(2.*tan(m_angle/2./180.*igl::PI)) ;
const double old_at_dist = m_at_dist;
m_at_dist = old_at_dist * s;
dolly(Vector3d(0,0,1)*(m_at_dist - old_at_dist));
assert((old_at-at()).squaredNorm() < DOUBLE_EPS);
}
}
inline void igl::Camera::turn_eye(const Eigen::Quaterniond & q)
{
using namespace Eigen;
Vector3d old_eye = eye();
// eye should be fixed
//
// eye_1 = R_1 * t_1 = eye_0
// t_1 = R_1' * eye_0
m_rotation_conj = q.conjugate();
m_translation = m_rotation_conj * old_eye;
assert((old_eye - eye()).squaredNorm() < DOUBLE_EPS);
}
inline void igl::Camera::orbit(const Eigen::Quaterniond & q)
{
using namespace Eigen;
Vector3d old_at = at();
// at should be fixed
//
// at_1 = R_1 * t_1 - R_1 * z = at_0
// t_1 = R_1' * (at_0 + R_1 * z)
m_rotation_conj = q.conjugate();
m_translation =
m_rotation_conj *
(old_at +
m_rotation_conj.conjugate() * Vector3d(0,0,1) * m_at_dist);
assert((old_at - at()).squaredNorm() < DOUBLE_EPS);
}
inline void igl::Camera::look_at(
const Eigen::Vector3d & eye,
const Eigen::Vector3d & at,
const Eigen::Vector3d & up)
{
using namespace Eigen;
using namespace std;
// http://www.opengl.org/sdk/docs/man2/xhtml/gluLookAt.xml
// Normalize vector from at to eye
Vector3d F = eye-at;
m_at_dist = F.norm();
F.normalize();
// Project up onto plane orthogonal to F and normalize
assert(up.cross(F).norm() > DOUBLE_EPS && "(eye-at) x up ≈ 0");
const Vector3d proj_up = (up-(up.dot(F))*F).normalized();
Quaterniond a,b;
a.setFromTwoVectors(Vector3d(0,0,-1),-F);
b.setFromTwoVectors(a*Vector3d(0,1,0),proj_up);
m_rotation_conj = (b*a).conjugate();
m_translation = m_rotation_conj * eye;
//cout<<"m_at_dist: "<<m_at_dist<<endl;
//cout<<"proj_up: "<<proj_up.transpose()<<endl;
//cout<<"F: "<<F.transpose()<<endl;
//cout<<"eye(): "<<this->eye().transpose()<<endl;
//cout<<"at(): "<<this->at().transpose()<<endl;
//cout<<"eye()-at(): "<<(this->eye()-this->at()).normalized().transpose()<<endl;
//cout<<"eye-this->eye(): "<<(eye-this->eye()).squaredNorm()<<endl;
assert( (eye-this->eye()).squaredNorm() < DOUBLE_EPS);
//assert((F-(this->eye()-this->at()).normalized()).squaredNorm() <
// DOUBLE_EPS);
assert( (at-this->at()).squaredNorm() < DOUBLE_EPS);
//assert( (proj_up-this->up()).squaredNorm() < DOUBLE_EPS);
}
#endif

View File

@@ -10,13 +10,17 @@
#include "igl_inline.h"
namespace igl
{
// Define a standard value for double epsilon
/// Standard value for double epsilon
const double DOUBLE_EPS = 1.0e-14;
/// Standard value for double epsilon²
const double DOUBLE_EPS_SQ = 1.0e-28;
/// Standard value for single epsilon
const float FLOAT_EPS = 1.0e-7f;
/// Standard value for single epsilon²
const float FLOAT_EPS_SQ = 1.0e-14f;
// Function returning EPS for corresponding type
/// Function returning EPS for corresponding type
template <typename S_type> IGL_INLINE S_type EPS();
/// Function returning EPS_SQ for corresponding type
template <typename S_type> IGL_INLINE S_type EPS_SQ();
// Template specializations for float and double
template <> IGL_INLINE float EPS<float>();

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,21 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Jérémie Dumas <jeremie.dumas@ens-lyon.org>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.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_FILEENCODING_H
#define IGL_FILEENCODING_H
namespace igl
{
/// File encoding types for writing files.
enum class FileEncoding {
Binary,
Ascii
};
}
#endif

View File

@@ -0,0 +1,64 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Jérémie Dumas <jeremie.dumas@ens-lyon.org>
// Copyright (C) 2021 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_FILEMEMORYSTREAM_H
#define IGL_FILEMEMORYSTREAM_H
#include "igl_inline.h"
#include <streambuf>
#include <istream>
#include <string>
namespace igl {
struct FileMemoryBuffer : public std::streambuf
{
char *p_start{nullptr};
char *p_end{nullptr};
size_t size;
FileMemoryBuffer(char const *first_elem, size_t size)
: p_start(const_cast<char *>(first_elem)), p_end(p_start + size),
size(size)
{
setg(p_start, p_start, p_end);
}
pos_type seekoff(
off_type off,
std::ios_base::seekdir dir,
std::ios_base::openmode /*which*/) override
{
if (dir == std::ios_base::cur)
{
gbump(static_cast<int>(off));
}else
{
setg(p_start,(dir==std::ios_base::beg ? p_start : p_end) + off,p_end);
}
return gptr() - p_start;
}
pos_type seekpos(pos_type pos, std::ios_base::openmode which) override
{
return seekoff(pos, std::ios_base::beg, which);
}
};
/// Class to convert a FILE * to an std::istream
struct FileMemoryStream : virtual FileMemoryBuffer, public std::istream
{
FileMemoryStream( char const *first_elem, size_t size)
: FileMemoryBuffer(first_elem, size),
std::istream( static_cast<std::streambuf *>(this))
{}
};
}
#endif

View File

@@ -10,9 +10,9 @@
template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
IGL_INLINE igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::HalfEdgeIterator(
const Eigen::PlainObjectBase<DerivedF>& _F,
const Eigen::PlainObjectBase<DerivedFF>& _FF,
const Eigen::PlainObjectBase<DerivedFFi>& _FFi,
const Eigen::MatrixBase<DerivedF>& _F,
const Eigen::MatrixBase<DerivedFF>& _FF,
const Eigen::MatrixBase<DerivedFFi>& _FFi,
int _fi,
int _ei,
bool _reverse
@@ -63,10 +63,10 @@ IGL_INLINE bool igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::isBorder()
/*!
* Returns the next edge skipping the border
* _________
* /\ c | b /\
* / \ | / \
* / d \ | / a \
* /______\|/______\
* ╱╲ c | b ╱╲
* |
* d | a
* ______╲|______
* v
* In this example, if a and d are of-border and the pos is iterating counterclockwise, this method iterate through the faces incident on vertex v,
* producing the sequence a, b, c, d, a, b, c, ...
@@ -138,8 +138,8 @@ IGL_INLINE bool igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::operator==
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> >::HalfEdgeIterator(Eigen::PlainObjectBase<Eigen::Matrix<int, -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> > const&, int, int, bool);
template igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::HalfEdgeIterator(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -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&, int, int, bool);
template igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> >::HalfEdgeIterator(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, int, int, bool);
template igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::HalfEdgeIterator(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, int, bool);
template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::NextFE();
template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Ei();
template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Ei();
@@ -147,12 +147,16 @@ template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen:
template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> >::Fi();
template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> >::NextFE();
template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Vi();
template igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::HalfEdgeIterator(Eigen::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&, int, int, bool);
template igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::HalfEdgeIterator(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, int, bool);
template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Fi();
template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::flipE();
template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >::flipE();
template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::flipF();
template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >::flipF();
template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::flipV();
template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::operator==(igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Fi();
template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::NextFE();
template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >::isBorder();
template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::isBorder();
#endif

View File

@@ -11,35 +11,24 @@
#include <Eigen/Core>
#include <vector>
#include <igl/igl_inline.h>
#include "igl_inline.h"
// This file violates many of the libigl style guidelines.
namespace igl
{
// HalfEdgeIterator - Fake halfedge for fast and easy navigation
// on triangle meshes with vertex_triangle_adjacency and
// triangle_triangle adjacency
//
// Note: this is different to classical Half Edge data structure.
// Instead, it follows cell-tuple in [Brisson, 1989]
// "Representing geometric structures in d dimensions: topology and order."
// This class can achieve local navigation similar to half edge in OpenMesh
// But the logic behind each atom operation is different.
// So this should be more properly called TriangleTupleIterator.
//
// Each tuple contains information on (face, edge, vertex)
// and encoded by (face, edge \in {0,1,2}, bool reverse)
//
// Inputs:
// F #F by 3 list of "faces"
// FF #F by 3 list of triangle-triangle adjacency.
// FFi #F by 3 list of FF inverse. For FF and FFi, refer to
// "triangle_triangle_adjacency.h"
// Usages:
// FlipF/E/V changes solely one actual face/edge/vertex resp.
// NextFE iterates through one-ring of a vertex robustly.
//
/// Fake halfedge for fast and easy navigation
/// on triangle meshes with vertex_triangle_adjacency and
/// triangle_triangle adjacency
///
/// Note: this is different to classical Half Edge data structure.
/// Instead, it follows cell-tuple in [Brisson, 1989]
/// "Representing geometric structures in d dimensions: topology and order."
/// This class can achieve local navigation similar to half edge in OpenMesh
/// But the logic behind each atom operation is different.
/// So this should be more properly called TriangleTupleIterator.
///
/// Each tuple contains information on (face, edge, vertex)
/// and encoded by (face, edge \in {0,1,2}, bool reverse)
template <
typename DerivedF,
typename DerivedFF,
@@ -47,51 +36,66 @@ namespace igl
class HalfEdgeIterator
{
public:
// Init the HalfEdgeIterator by specifying Face,Edge Index and Orientation
/// Init the HalfEdgeIterator by specifying Face,Edge Index and Orientation
///
/// @param[in] F #F by 3 list of "faces"
/// @param[in] FF #F by 3 list of triangle-triangle adjacency.
/// @param[in] FFi #F by 3 list of FF inverse. For FF and FFi, refer to
/// "triangle_triangle_adjacency.h"
/// @param[in] _fi index of the selected face
/// @param[in] _ii index of the selected face
/// @param[in] _reverse orientation of the selected face
IGL_INLINE HalfEdgeIterator(
const Eigen::PlainObjectBase<DerivedF>& _F,
const Eigen::PlainObjectBase<DerivedFF>& _FF,
const Eigen::PlainObjectBase<DerivedFFi>& _FFi,
const Eigen::MatrixBase<DerivedF>& _F,
const Eigen::MatrixBase<DerivedFF>& _FF,
const Eigen::MatrixBase<DerivedFFi>& _FFi,
int _fi,
int _ei,
bool _reverse = false
);
// Change Face
/// Change Face
IGL_INLINE void flipF();
// Change Edge
/// Change Edge
IGL_INLINE void flipE();
// Change Vertex
/// Change Vertex
IGL_INLINE void flipV();
/// Determine if on border.
/// @returns true if the current edge is on the border
IGL_INLINE bool isBorder();
/*!
* Returns the next edge skipping the border
* _________
* /\ c | b /\
* / \ | / \
* / d \ | / a \
* /______\|/______\
* v
* In this example, if a and d are of-border and the pos is iterating
counterclockwise, this method iterate through the faces incident on vertex
v,
* producing the sequence a, b, c, d, a, b, c, ...
*/
/// Change to next edge skipping the border
/// _________
/// ╱╲ c | b ╱╲
/// ╲ |
/// d ╲ | a
/// ______╲|______╲
/// v
/// In this example, if a and d are of-border and the pos is iterating
/// counterclockwise, this method iterate through the faces incident on vertex
/// v,
/// producing the sequence a, b, c, d, a, b, c, ...
///
/// @returns true if the next edge is not on the border
IGL_INLINE bool NextFE();
// Get vertex index
/// Get vertex index
/// @return vertex index
IGL_INLINE int Vi();
// Get face index
/// Get face index
/// @return face index
IGL_INLINE int Fi();
// Get edge index
/// Get edge index
/// @return edge index
IGL_INLINE int Ei();
/// Check if two HalfEdgeIterator are the same
/// @return true if two HalfEdgeIterator are the same
IGL_INLINE bool operator==(HalfEdgeIterator& p2);
private:
@@ -100,9 +104,9 @@ namespace igl
bool reverse;
// All the same type? This is likely to break.
const Eigen::PlainObjectBase<DerivedF> & F;
const Eigen::PlainObjectBase<DerivedFF> & FF;
const Eigen::PlainObjectBase<DerivedFFi> & FFi;
const Eigen::MatrixBase<DerivedF> & F;
const Eigen::MatrixBase<DerivedFF> & FF;
const Eigen::MatrixBase<DerivedFFi> & FFi;
};
}

View File

@@ -11,15 +11,21 @@
namespace igl
{
// Reimplementation of the embree::Hit struct from embree1.0
//
// TODO: template on floating point type
/// Reimplementation of the embree::Hit struct from embree1.0
///
template <typename Scalar>
struct Hit
{
int id; // primitive id
int gid; // geometry id
float u,v; // barycentric coordinates
float t; // distance = direction*t to intersection
/// primitive id
int id;
/// geometry id (not used)
int gid;
/// barycentric coordinates so that
/// pos = V.row(F(id,0))*(1-u-v)+V.row(F(id,1))*u+V.row(F(id,2))*v;
Scalar u,v;
/// parametric distance so that
/// pos = origin + t * dir
Scalar t;
};
}
#endif

View File

@@ -0,0 +1,9 @@
// https://stackoverflow.com/a/985807/148668
#include <cassert>
#ifndef IGL_ASSERT
#ifdef NDEBUG
#define IGL_ASSERT(x) do { (void)sizeof(x);} while (0)
#else
#define IGL_ASSERT(x) assert(x)
#endif
#endif

View File

@@ -7,12 +7,9 @@
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_INDEXCOMPARISON_H
#define IGL_INDEXCOMPARISON_H
#include <iostream>
namespace igl{
// Comparison struct used by sort
// http://bytes.com/topic/c/answers/132045-sort-get-index
// For use with functions like std::sort
/// Comparison struct used by sort
/// http://bytes.com/topic/c/answers/132045-sort-get-index
template<class T> struct IndexLessThan
{
IndexLessThan(const T arr) : arr(arr) {}
@@ -23,7 +20,7 @@ namespace igl{
const T arr;
};
// For use with functions like std::unique
/// Comparison struct used by unique
template<class T> struct IndexEquals
{
IndexEquals(const T arr) : arr(arr) {}
@@ -34,7 +31,7 @@ namespace igl{
const T arr;
};
// For use with functions like std::sort
/// Comparison struct for vectors for use with functions like std::sort
template<class T> struct IndexVectorLessThan
{
IndexVectorLessThan(const T & vec) : vec ( vec) {}
@@ -45,7 +42,7 @@ namespace igl{
const T & vec;
};
// For use with functions like std::sort
/// Comparison struct for use with functions like std::sort
template<class T> struct IndexDimLessThan
{
IndexDimLessThan(const T & mat,const int & dim, const int & j) :
@@ -68,7 +65,7 @@ namespace igl{
const int & j;
};
// For use with functions like std::sort
/// Comparison struct For use with functions like std::sort
template<class T> struct IndexRowLessThan
{
IndexRowLessThan(const T & mat) : mat ( mat) {}
@@ -92,7 +89,7 @@ namespace igl{
const T & mat;
};
// For use with functions like std::sort
/// Comparison struct for use with functions like std::sort
template<class T> struct IndexRowEquals
{
IndexRowEquals(const T & mat) : mat ( mat) {}

View File

@@ -1,33 +1,42 @@
#ifndef IGL_LINSPACED_H
#define IGL_LINSPACED_H
#include <Eigen/Core>
// This function is not intended to be a permanent function of libigl. Rather
// it is a "drop-in" workaround for documented bug in Eigen:
// http://eigen.tuxfamily.org/bz/show_bug.cgi?id=1383
//
// Replace:
//
// Eigen::VectorXi::LinSpaced(size,low,high);
//
// With:
//
// igl::LinSpaced<Eigen::VectorXi>(size,low,high);
//
// Specifcally, this version will _always_ return an empty vector if size==0,
// regardless of the values for low and high. If size != 0, then this simply
// returns the result of Eigen::Derived::LinSpaced.
//
// Until this bug is fixed, we should also avoid calls to the member function
// `.setLinSpaced`. This means replacing:
//
// a.setLinSpaced(size,low,high);
//
// with
//
// a = igl::LinSpaced<decltype(a) >(size,low,high);
//
/// @file LinSpaced.h
///
/// This function is not intended to be a permanent function of libigl. Rather
/// it is a "drop-in" workaround for documented bug in Eigen:
/// http://eigen.tuxfamily.org/bz/show_bug.cgi?id=1383
///
/// Replace:
///
/// Eigen::VectorXi::LinSpaced(size,low,high);
///
/// With:
///
/// igl::LinSpaced<Eigen::VectorXi>(size,low,high);
///
/// Specifcally, this version will _always_ return an empty vector if size==0,
/// regardless of the values for low and high. If size != 0, then this simply
/// returns the result of Eigen::Derived::LinSpaced.
///
/// Until this bug is fixed, we should also avoid calls to the member function
/// `.setLinSpaced`. This means replacing:
///
/// a.setLinSpaced(size,low,high);
///
/// with
///
/// a = igl::LinSpaced<decltype(a) >(size,low,high);
///
namespace igl
{
/// Replacement for Eigen::DenseBase::LinSpaced
/// @param[in] size number of elements
/// @param[in] low first element
/// @param[in] high last element
/// @return vector of size elements linearly spaced between low and
///
/// \fileinfo
template <typename Derived>
//inline typename Eigen::DenseBase< Derived >::RandomAccessLinSpacedReturnType
inline Derived LinSpaced(

View File

@@ -0,0 +1,26 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2018 Zhongshi Jiang <jiangzs@nyu.edu>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_MAPPINGENERGYTYPE_H
#define IGL_MAPPINGENERGYTYPE_H
namespace igl
{
/// Energy Types used for Parameterization/Mapping.
/// Refer to SLIM [Rabinovich et al. 2017] for more details
// Todo: Integrate with ARAPEnergyType
enum MappingEnergyType
{
ARAP = 0,
LOG_ARAP = 1,
SYMMETRIC_DIRICHLET = 2,
CONFORMAL = 3,
EXP_CONFORMAL = 4,
EXP_SYMMETRIC_DIRICHLET = 5,
NUM_SLIM_ENERGY_TYPES = 6
};
}
#endif

View File

@@ -9,13 +9,20 @@
#define IGL_MESH_BOOLEAN_TYPE_H
namespace igl
{
/// Boolean operation types
enum MeshBooleanType
{
/// A B
MESH_BOOLEAN_TYPE_UNION = 0,
/// A ∩ B
MESH_BOOLEAN_TYPE_INTERSECT = 1,
/// A \ B
MESH_BOOLEAN_TYPE_MINUS = 2,
/// A ⊕ B
MESH_BOOLEAN_TYPE_XOR = 3,
/// Resolve intersections without removing any non-coplanar faces
MESH_BOOLEAN_TYPE_RESOLVE = 4,
/// Total number of Boolean options
NUM_MESH_BOOLEAN_TYPES = 5
};
};

View File

@@ -0,0 +1,497 @@
// based on MSH reader from PyMesh
// Copyright (c) 2015 Qingnan Zhou <qzhou@adobe.com>
// Copyright (C) 2020 Vladimir Fonov <vladimir.fonov@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "MshLoader.h"
#include <cassert>
#include <iostream>
#include <sstream>
#include <vector>
#include <string.h>
namespace igl {
// helper function
void inline _msh_eat_white_space(std::ifstream& fin) {
char next = fin.peek();
while (next == '\n' || next == ' ' || next == '\t' || next == '\r') {
fin.get();
next = fin.peek();
}
}
}
IGL_INLINE igl::MshLoader::MshLoader(const std::string &filename) {
std::ifstream fin(filename, std::ios::in | std::ios::binary);
if (!fin.is_open()) {
std::stringstream err_msg;
err_msg << "failed to open file \"" << filename << "\"";
throw std::ios_base::failure(err_msg.str());
}
// Parse header
std::string buf;
double version;
int type;
fin >> buf;
if (buf != "$MeshFormat") { throw std::runtime_error("Unexpected .msh format"); }
fin >> version >> type >> m_data_size;
m_binary = (type == 1);
if(version>2.2 || version<2.0)
{
// probably unsupported version
std::stringstream err_msg;
err_msg << "Error: Unsupported file version:" << version << std::endl;
throw std::runtime_error(err_msg.str());
}
// Some sanity check.
if (m_data_size != 8) {
std::stringstream err_msg;
err_msg << "Error: data size must be 8 bytes." << std::endl;
throw std::runtime_error(err_msg.str());
}
if (sizeof(int) != 4) {
std::stringstream err_msg;
err_msg << "Error: code must be compiled with int size 4 bytes." << std::endl;
throw std::runtime_error(err_msg.str());
}
// Read in extra info from binary header.
if (m_binary) {
int one;
igl::_msh_eat_white_space(fin);
fin.read(reinterpret_cast<char*>(&one), sizeof(int));
if (one != 1) {
std::stringstream err_msg;
err_msg << "Binary msh file " << filename
<< " is saved with different endianness than this machine."
<< std::endl;
throw std::runtime_error(err_msg.str());
}
}
fin >> buf;
if (buf != "$EndMeshFormat")
{
std::stringstream err_msg;
err_msg << "Unexpected contents in the file header." << std::endl;
throw std::runtime_error(err_msg.str());
}
while (!fin.eof()) {
buf.clear();
fin >> buf;
if (buf == "$Nodes") {
parse_nodes(fin);
fin >> buf;
if (buf != "$EndNodes") { throw std::runtime_error("Unexpected tag"); }
} else if (buf == "$Elements") {
parse_elements(fin);
fin >> buf;
if (buf != "$EndElements") { throw std::runtime_error("Unexpected tag"); }
} else if (buf == "$NodeData") {
parse_node_field(fin);
fin >> buf;
if (buf != "$EndNodeData") { throw std::runtime_error("Unexpected tag"); }
} else if (buf == "$ElementData") {
parse_element_field(fin);
fin >> buf;
if (buf != "$EndElementData") { throw std::runtime_error("Unexpected tag"); }
} else if (fin.eof()) {
break;
} else {
parse_unknown_field(fin, buf);
}
}
fin.close();
}
IGL_INLINE void igl::MshLoader::parse_nodes(std::ifstream& fin) {
size_t num_nodes;
fin >> num_nodes;
m_nodes.resize(num_nodes*3);
if (m_binary) {
size_t stride = (4+3*m_data_size);
size_t num_bytes = stride * num_nodes;
char* data = new char[num_bytes];
igl::_msh_eat_white_space(fin);
fin.read(data, num_bytes);
for (size_t i=0; i<num_nodes; i++) {
int node_idx;
memcpy(&node_idx, data+i*stride, sizeof(int));
node_idx-=1;
// directly move into vector storage
// this works only when m_data_size==sizeof(Float)==sizeof(double)
memcpy(&m_nodes[node_idx*3], data+i*stride + 4, m_data_size*3);
}
delete [] data;
} else {
int node_idx;
for (size_t i=0; i<num_nodes; i++) {
fin >> node_idx;
node_idx -= 1;
// here it's 3D node explicitly
fin >> m_nodes[node_idx*3]
>> m_nodes[node_idx*3+1]
>> m_nodes[node_idx*3+2];
}
}
}
IGL_INLINE void igl::MshLoader::parse_elements(std::ifstream& fin) {
m_elements_tags.resize(2); //hardcoded to have 2 tags
size_t num_elements;
fin >> num_elements;
size_t nodes_per_element;
if (m_binary) {
igl::_msh_eat_white_space(fin);
int elem_read = 0;
while (elem_read < num_elements) {
// Parse element header.
int elem_type, num_elems, num_tags;
fin.read((char*)&elem_type, sizeof(int));
fin.read((char*)&num_elems, sizeof(int));
fin.read((char*)&num_tags, sizeof(int));
nodes_per_element = num_nodes_per_elem_type(elem_type);
// store node info
for (size_t i=0; i<num_elems; i++) {
int elem_idx;
// all elements in the segment share the same elem_type and number of nodes per element
m_elements_types.push_back(elem_type);
m_elements_lengths.push_back(nodes_per_element);
fin.read((char*)&elem_idx, sizeof(int));
elem_idx -= 1;
m_elements_ids.push_back(elem_idx);
// read first two tags
for (size_t j=0; j<num_tags; j++) {
int tag;
fin.read((char*)&tag, sizeof(int));
if(j<2) m_elements_tags[j].push_back(tag);
}
for (size_t j=num_tags; j<2; j++)
m_elements_tags[j].push_back(-1); // fill up tags if less then 2
m_elements_nodes_idx.push_back(m_elements.size());
// Element values.
for (size_t j=0; j<nodes_per_element; j++) {
int idx;
fin.read((char*)&idx, sizeof(int));
m_elements.push_back(idx-1);
}
}
elem_read += num_elems;
}
} else {
for (size_t i=0; i<num_elements; i++) {
// Parse per element header
int elem_num, elem_type, num_tags;
fin >> elem_num >> elem_type >> num_tags;
// read tags.
for (size_t j=0; j<num_tags; j++) {
int tag;
fin >> tag;
if(j<2) m_elements_tags[j].push_back(tag);
}
for (size_t j=num_tags; j<2; j++)
m_elements_tags[j].push_back(-1); // fill up tags if less then 2
nodes_per_element = num_nodes_per_elem_type(elem_type);
m_elements_types.push_back(elem_type);
m_elements_lengths.push_back(nodes_per_element);
elem_num -= 1;
m_elements_ids.push_back(elem_num);
m_elements_nodes_idx.push_back(m_elements.size());
// Parse node idx.
for (size_t j=0; j<nodes_per_element; j++) {
int idx;
fin >> idx;
m_elements.push_back(idx-1); // msh index starts from 1.
}
}
}
// debug
assert(m_elements_types.size() == m_elements_ids.size());
assert(m_elements_tags[0].size() == m_elements_ids.size());
assert(m_elements_tags[1].size() == m_elements_ids.size());
assert(m_elements_lengths.size() == m_elements_ids.size());
}
IGL_INLINE void igl::MshLoader::parse_node_field( std::ifstream& fin ) {
size_t num_string_tags;
size_t num_real_tags;
size_t num_int_tags;
fin >> num_string_tags;
std::vector<std::string> str_tags(num_string_tags);
for (size_t i=0; i<num_string_tags; i++) {
igl::_msh_eat_white_space(fin);
if (fin.peek() == '\"') {
// Handle field name between quotes.
char buf[128];
fin.get(); // remove the quote at the beginning.
fin.getline(buf, 128, '\"');
str_tags[i] = std::string(buf);
} else {
fin >> str_tags[i];
}
}
fin >> num_real_tags;
std::vector<Float> real_tags(num_real_tags);
for (size_t i=0; i<num_real_tags; i++)
fin >> real_tags[i];
fin >> num_int_tags;
std::vector<int> int_tags(num_int_tags);
for (size_t i=0; i<num_int_tags; i++)
fin >> int_tags[i];
if (num_string_tags <= 0 || num_int_tags <= 2) {
throw std::runtime_error("Unexpected number of field tags");
}
std::string fieldname = str_tags[0];
int num_components = int_tags[1];
int num_entries = int_tags[2];
std::vector<Float> field( num_entries*num_components );
if (m_binary) {
size_t num_bytes = (num_components * m_data_size + 4) * num_entries;
char* data = new char[num_bytes];
igl::_msh_eat_white_space(fin);
fin.read(data, num_bytes);
for (size_t i=0; i<num_entries; i++) {
int node_idx;
memcpy(&node_idx,&data[i*(4+num_components*m_data_size)],4);
if(node_idx<1) throw std::runtime_error("Negative or zero index");
node_idx -= 1;
if(node_idx>=num_entries) throw std::runtime_error("Index too big");
size_t base_idx = i*(4+num_components*m_data_size) + 4;
// TODO: make this work when m_data_size != sizeof(double) ?
memcpy(&field[node_idx*num_components], &data[base_idx], num_components*m_data_size);
}
delete [] data;
} else {
int node_idx;
for (size_t i=0; i<num_entries; i++) {
fin >> node_idx;
node_idx -= 1;
for (size_t j=0; j<num_components; j++) {
fin >> field[node_idx*num_components+j];
}
}
}
m_node_fields_names.push_back(fieldname);
m_node_fields.push_back(field);
m_node_fields_components.push_back(num_components);
}
IGL_INLINE void igl::MshLoader::parse_element_field(std::ifstream& fin) {
size_t num_string_tags;
size_t num_real_tags;
size_t num_int_tags;
fin >> num_string_tags;
std::vector<std::string> str_tags(num_string_tags);
for (size_t i=0; i<num_string_tags; i++) {
igl::_msh_eat_white_space(fin);
if (fin.peek() == '\"') {
// Handle field name between quoates.
char buf[128];
fin.get(); // remove the quote at the beginning.
fin.getline(buf, 128, '\"');
str_tags[i] = buf;
} else {
fin >> str_tags[i];
}
}
fin >> num_real_tags;
std::vector<Float> real_tags(num_real_tags);
for (size_t i=0; i<num_real_tags; i++)
fin >> real_tags[i];
fin >> num_int_tags;
std::vector<int> int_tags(num_int_tags);
for (size_t i=0; i<num_int_tags; i++)
fin >> int_tags[i];
if (num_string_tags <= 0 || num_int_tags <= 2) {
throw std::runtime_error("Invalid file format");
}
std::string fieldname = str_tags[0];
int num_components = int_tags[1];
int num_entries = int_tags[2];
std::vector<Float> field(num_entries*num_components);
if (m_binary) {
size_t num_bytes = (num_components * m_data_size + 4) * num_entries;
char* data = new char[num_bytes];
igl::_msh_eat_white_space(fin);
fin.read(data, num_bytes);
for (int i=0; i<num_entries; i++) {
int elem_idx;
// works with sizeof(int)==4
memcpy(&elem_idx, &data[i*(4+num_components*m_data_size)],4);
elem_idx -= 1;
// directly copy data into vector storage space
memcpy(&field[elem_idx*num_components], &data[i*(4+num_components*m_data_size) + 4], m_data_size*num_components);
}
delete [] data;
} else {
int elem_idx;
for (size_t i=0; i<num_entries; i++) {
fin >> elem_idx;
elem_idx -= 1;
for (size_t j=0; j<num_components; j++) {
fin >> field[elem_idx*num_components+j];
}
}
}
m_element_fields_names.push_back(fieldname);
m_element_fields.push_back(field);
m_element_fields_components.push_back(num_components);
}
IGL_INLINE void igl::MshLoader::parse_unknown_field(std::ifstream& fin,
const std::string& fieldname) {
std::cerr << "Warning: \"" << fieldname << "\" not supported yet. Ignored." << std::endl;
std::string endmark = fieldname.substr(0,1) + "End"
+ fieldname.substr(1,fieldname.size()-1);
std::string buf("");
while (buf != endmark && !fin.eof()) {
fin >> buf;
}
}
IGL_INLINE int igl::MshLoader::num_nodes_per_elem_type(int elem_type) {
int nodes_per_element = 0;
switch (elem_type) {
case ELEMENT_LINE: // 2-node line
nodes_per_element = 2;
break;
case ELEMENT_TRI:
nodes_per_element = 3; // 3-node triangle
break;
case ELEMENT_QUAD:
nodes_per_element = 4; // 5-node quad
break;
case ELEMENT_TET:
nodes_per_element = 4; // 4-node tetrahedra
break;
case ELEMENT_HEX: // 8-node hexahedron
nodes_per_element = 8;
break;
case ELEMENT_PRISM: // 6-node prism
nodes_per_element = 6;
break;
case ELEMENT_LINE_2ND_ORDER:
nodes_per_element = 3;
break;
case ELEMENT_TRI_2ND_ORDER:
nodes_per_element = 6;
break;
case ELEMENT_QUAD_2ND_ORDER:
nodes_per_element = 9;
break;
case ELEMENT_TET_2ND_ORDER:
nodes_per_element = 10;
break;
case ELEMENT_HEX_2ND_ORDER:
nodes_per_element = 27;
break;
case ELEMENT_PRISM_2ND_ORDER:
nodes_per_element = 18;
break;
case ELEMENT_PYRAMID_2ND_ORDER:
nodes_per_element = 14;
break;
case ELEMENT_POINT: // 1-node point
nodes_per_element = 1;
break;
default:
std::stringstream err_msg;
err_msg << "Element type (" << elem_type << ") is not supported yet."
<< std::endl;
throw std::runtime_error(err_msg.str());
}
return nodes_per_element;
}
IGL_INLINE bool igl::MshLoader::is_element_map_identity() const
{
for(int i=0;i<m_elements_ids.size();i++) {
int id=m_elements_ids[i];
if (id!=i) return false;
}
return true;
}
IGL_INLINE void igl::MshLoader::index_structures(int tag_column)
{
//cleanup
m_structure_index.clear();
m_structures.clear();
m_structure_length.clear();
//index structure tags
for(auto i=0; i != m_elements_tags[tag_column].size(); ++i )
{
m_structure_index.insert(
std::pair<msh_struct,int>(
msh_struct( m_elements_tags[tag_column][i],
m_elements_types[i]), i)
);
}
// identify unique structures
std::vector<StructIndex::value_type> _unique_structs;
std::unique_copy(std::begin(m_structure_index),
std::end(m_structure_index),
std::back_inserter(_unique_structs),
[](const StructIndex::value_type &c1, const StructIndex::value_type &c2)
{ return c1.first == c2.first; });
std::for_each( _unique_structs.begin(), _unique_structs.end(),
[this](const StructIndex::value_type &n){ this->m_structures.push_back(n.first); });
for(auto t = m_structures.begin(); t != m_structures.end(); ++t)
{
// identify all elements corresponding to this tag
auto structure_range = m_structure_index.equal_range( *t );
int cnt=0;
for(auto i=structure_range.first; i!=structure_range.second; i++)
cnt++;
m_structure_length.insert( std::pair<msh_struct,int>( *t, cnt));
}
}

View File

@@ -0,0 +1,192 @@
// based on MSH reader from PyMesh
// Copyright (c) 2015 Qingnan Zhou <qzhou@adobe.com>
// Copyright (C) 2020 Vladimir Fonov <vladimir.fonov@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_MSH_LOADER_H
#define IGL_MSH_LOADER_H
#include "igl_inline.h"
#include <fstream>
#include <map>
#include <string>
#include <vector>
#include <algorithm>
namespace igl {
/// Class for loading information from .msh file
/// depends only on c++stl library
class MshLoader {
public:
struct msh_struct {
int tag,el_type;
msh_struct(int _tag=0,int _type=0):
tag(_tag),el_type(_type){}
bool operator== (const msh_struct& a) const {
return this->tag==a.tag &&
this->el_type==a.el_type;
}
bool operator< (const msh_struct& a) const {
return (this->tag*100+this->el_type) <
(a.tag*100+a.el_type);
}
};
typedef double Float;
typedef std::vector<int> IndexVector;
typedef std::vector<int> IntVector;
typedef std::vector<Float> FloatVector;
typedef std::vector<FloatVector> FloatField;
typedef std::vector<IntVector> IntField;
typedef std::vector<std::string> FieldNames;
typedef std::multimap<msh_struct,int> StructIndex;
typedef std::vector<msh_struct> StructVector;
enum {ELEMENT_LINE=1, ELEMENT_TRI=2, ELEMENT_QUAD=3,
ELEMENT_TET=4, ELEMENT_HEX=5, ELEMENT_PRISM=6,
ELEMENT_PYRAMID=7,
// 2nd order elements
ELEMENT_LINE_2ND_ORDER=8, ELEMENT_TRI_2ND_ORDER=9,
ELEMENT_QUAD_2ND_ORDER=10,ELEMENT_TET_2ND_ORDER=11,
ELEMENT_HEX_2ND_ORDER=12, ELEMENT_PRISM_2ND_ORDER=13,
ELEMENT_PYRAMID_2ND_ORDER=14,
// other elements
ELEMENT_POINT=15 };
public:
/// Load a .msh file from a given path
/// @param[in] filename path to .msh
MshLoader(const std::string &filename);
public:
// get nodes , x,y,z sequentially
const FloatVector& get_nodes() const { return m_nodes; }
// get elements , identifying nodes that create an element
// variable length per element
const IndexVector& get_elements() const { return m_elements; }
// get element types
const IntVector& get_elements_types() const { return m_elements_types; }
// get element lengths
const IntVector& get_elements_lengths() const { return m_elements_lengths; }
// get element tags ( physical (0) and elementary (1) )
const IntField& get_elements_tags() const { return m_elements_tags; }
// get element IDs
const IntVector& get_elements_ids() const { return m_elements_ids; }
// get reverse index from node to element
const IndexVector& get_elements_nodes_idx() const { return m_elements_nodes_idx; }
// get fields assigned per node, all fields and components sequentially
const FloatField& get_node_fields() const { return m_node_fields;}
// get node field names,
const FieldNames& get_node_fields_names() const { return m_node_fields_names;}
// get number of node field components
const IntVector& get_node_fields_components() const {return m_node_fields_components;}
int get_node_field_components(size_t c) const
{
return m_node_fields_components[c];
}
// get fields assigned per element, all fields and components sequentially
const FloatField& get_element_fields() const { return m_element_fields;}
// get element field names
const FieldNames& get_element_fields_names() const { return m_element_fields_names;}
// get number of element field components
const IntVector& get_element_fields_components() const {return m_element_fields_components;}
int get_element_field_components(size_t c) const {
return m_element_fields_components[c];
}
// check if field is present at node level
bool is_node_field(const std::string& fieldname) const {
return (std::find(std::begin(m_node_fields_names),
std::end(m_node_fields_names),
fieldname) != std::end(m_node_fields_names) );
}
// check if field is present at element level
bool is_element_field(const std::string& fieldname) const {
return (std::find(std::begin(m_element_fields_names),
std::end(m_element_fields_names),
fieldname) != std::end(m_node_fields_names) );
}
// check if all elements have ids assigned sequentially
bool is_element_map_identity() const ;
// create tag index
// tag_column: ( physical (0) or elementary (1) ) specifying which tag to use
void index_structures(int tag_column);
// get tag index, call index_structure_tags first
const StructIndex& get_structure_index() const
{
return m_structure_index;
}
// get size of a structure identified by tag and element type
const StructIndex& get_structure_length() const
{
return m_structure_length;
}
//! get list of structures
const StructVector& get_structures() const
{
return m_structures;
}
public:
// helper function, calculate number of nodes associated with an element
static int num_nodes_per_elem_type(int elem_type);
private:
void parse_nodes(std::ifstream& fin);
void parse_elements(std::ifstream& fin);
void parse_node_field(std::ifstream& fin);
void parse_element_field(std::ifstream& fin);
void parse_unknown_field(std::ifstream& fin,
const std::string& fieldname);
private:
bool m_binary;
size_t m_data_size;
FloatVector m_nodes; // len x 3 vector
IndexVector m_elements; // linear array for nodes corresponding to each element
IndexVector m_elements_nodes_idx; // element indexes
IntVector m_elements_ids; // element id's
IntVector m_elements_types; // Element types
IntVector m_elements_lengths; // Element lengths
IntField m_elements_tags; // Element tags, currently 2xtags per element
FloatField m_node_fields; // Float field defined at each node
IntVector m_node_fields_components; // Number of components for node field
FieldNames m_node_fields_names; // Node field name
FloatField m_element_fields; // Float field defined at each element
IntVector m_element_fields_components; // Number of components for element field
FieldNames m_element_fields_names; // Element field name
StructIndex m_structure_index; // index tag ids
StructVector m_structures; // unique structures
StructIndex m_structure_length; // length of structures with consistent element type
};
} //igl
#ifndef IGL_STATIC_LIBRARY
# include "MshLoader.cpp"
#endif
#endif //IGL_MSH_LOADER_H

View File

@@ -0,0 +1,343 @@
// based on MSH writer from PyMesh
// Copyright (c) 2015 Qingnan Zhou <qzhou@adobe.com>
// Copyright (C) 2020 Vladimir Fonov <vladimir.fonov@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "MshSaver.h"
#include <cassert>
#include <iostream>
#include <sstream>
#include <exception>
IGL_INLINE igl::MshSaver::MshSaver(const std::string& filename, bool binary) :
m_binary(binary), m_num_nodes(0), m_num_elements(0) {
if (!m_binary) {
fout.open(filename.c_str(), std::fstream::out);
} else {
fout.open(filename.c_str(), std::fstream::binary);
}
if (!fout) {
std::stringstream err_msg;
err_msg << "Error opening " << filename << " to write msh file." << std::endl;
throw std::ios_base::failure(err_msg.str());
}
}
IGL_INLINE igl::MshSaver::~MshSaver() {
fout.close();
}
IGL_INLINE void igl::MshSaver::save_mesh(
const FloatVector& nodes,
const IndexVector& elements,
const IntVector& element_lengths,
const IntVector& element_types,
const IntVector& element_tags
) {
save_header();
save_nodes(nodes);
save_elements(elements, element_lengths, element_types, element_tags );
}
IGL_INLINE void igl::MshSaver::save_header() {
if (!m_binary) {
fout << "$MeshFormat" << std::endl;
fout << "2.2 0 " << sizeof(double) << std::endl;
fout << "$EndMeshFormat" << std::endl;
fout.precision(17);
} else {
fout << "$MeshFormat" << std::endl;
fout << "2.2 1 " << sizeof(double) << std::endl;
int one = 1;
fout.write((char*)&one, sizeof(int));
fout << "\n$EndMeshFormat" << std::endl;
}
fout.flush();
}
IGL_INLINE void igl::MshSaver::save_nodes(const FloatVector& nodes) {
// Save nodes.
// 3D hadrcoded
m_num_nodes = nodes.size() / 3;
fout << "$Nodes" << std::endl;
fout << m_num_nodes << std::endl;
if (!m_binary) {
for (size_t i=0; i<nodes.size(); i+=3) {
//const VectorF& v = nodes.segment(i,m_dim);
int node_idx = i/3 + 1;
fout << node_idx << " " << nodes[i] << " " << nodes[i+1] << " " << nodes[i+2] << std::endl;
}
} else {
for (size_t i=0; i<nodes.size(); i+=3) {
//const VectorF& v = nodes.segment(i,m_dim);
int node_idx = i/3 + 1;
fout.write((const char*)&node_idx, sizeof(int));
fout.write((const char*)&nodes[i], sizeof(Float)*3);
}
}
fout << "$EndNodes" << std::endl;
fout.flush();
}
IGL_INLINE void igl::MshSaver::save_elements(const IndexVector& elements,
const IntVector& element_lengths,
const IntVector& element_types,
const IntVector& element_tags)
{
m_num_elements = element_tags.size();
assert(element_lengths.size() == element_types.size() );
assert(element_lengths.size() == element_tags.size() );
// TODO: sum up all lengths
// Save elements.
// node inxes are 1-based
fout << "$Elements" << std::endl;
fout << m_num_elements << std::endl;
if (m_num_elements > 0) {
//int elem_type = el_type;
//int tags = 0;
if (!m_binary) {
size_t el_ptr=0;
for (size_t i=0;i<m_num_elements;++i) {
int elem_num = (int) i + 1;
///VectorI elem = elements.segment(i, nodes_per_element) + VectorI::Ones(nodes_per_element);
// hardcoded: duplicate tags (I don't know why)
fout << elem_num << " " << element_types[i] << " " << 2 << " "<< element_tags[i] << " "<< element_tags[i] << " ";
for (size_t j=0; j<element_lengths[i]; j++) {
fout << elements[el_ptr + j] + 1 << " ";
}
fout << std::endl;
el_ptr+=element_lengths[i];
}
} else {
size_t el_ptr=0,i=0;
while(i<m_num_elements) {
// write elements in consistent chunks
// TODO: refactor this code to be able to specify different elements
// more effeciently
int elem_type=-1;
int elem_len=-1;
size_t j=i;
for(;j<m_num_elements;++j)
{
if( elem_type==-1 )
{
elem_type=element_types[j];
elem_len=element_lengths[j];
} else if( elem_type!=element_types[j] ||
elem_len!=element_lengths[j]) {
break; // found the edge of the segment
}
}
//hardcoded: 2 tags
int num_elems=j-i, num_tags=2;
fout.write((const char*)& elem_type, sizeof(int));
fout.write((const char*)& num_elems, sizeof(int));
fout.write((const char*)& num_tags, sizeof(int));
for(int k=0;k<num_elems; ++k,++i){
int elem_num = (int )i + 1;
fout.write((const char*)&elem_num, sizeof(int));
// HACK: hardcoded 2 tags
fout.write((const char*)& element_tags[i], sizeof(int));
fout.write((const char*)& element_tags[i], sizeof(int));
for (size_t e=0; e<elem_len; e++) {
int _elem = static_cast<int>( elements[el_ptr + e] )+1;
fout.write((const char*)&_elem, sizeof(int));
}
el_ptr+=elem_len;
}
}
}
}
fout << "$EndElements" << std::endl;
fout.flush();
}
IGL_INLINE void igl::MshSaver::save_scalar_field(const std::string& fieldname, const FloatVector& field) {
assert(field.size() == m_num_nodes);
fout << "$NodeData" << std::endl;
fout << "1" << std::endl; // num string tags.
fout << "\"" << fieldname << "\"" << std::endl;
fout << "1" << std::endl; // num real tags.
fout << "0.0" << std::endl; // time value.
fout << "3" << std::endl; // num int tags.
fout << "0" << std::endl; // the time step
fout << "1" << std::endl; // 1-component scalar field.
fout << m_num_nodes << std::endl; // number of nodes
if (m_binary) {
for (size_t i=0; i<m_num_nodes; i++) {
int node_idx = i+1;
fout.write((char*)&node_idx, sizeof(int));
fout.write((char*)&field[i], sizeof(Float));
}
} else {
for (size_t i=0; i<m_num_nodes; i++) {
int node_idx = i+1;
fout << node_idx << " " << field[i] << std::endl;
}
}
fout << "$EndNodeData" << std::endl;
fout.flush();
}
IGL_INLINE void igl::MshSaver::save_vector_field(const std::string& fieldname, const FloatVector& field) {
assert(field.size() == 3 * m_num_nodes);
fout << "$NodeData" << std::endl;
fout << "1" << std::endl; // num string tags.
fout << "\"" << fieldname << "\"" << std::endl;
fout << "1" << std::endl; // num real tags.
fout << "0.0" << std::endl; // time value.
fout << "3" << std::endl; // num int tags.
fout << "0" << std::endl; // the time step
fout << "3" << std::endl; // 3-component vector field.
fout << m_num_nodes << std::endl; // number of nodes
if (m_binary) {
for (size_t i=0; i<m_num_nodes; i++) {
int node_idx = i+1;
fout.write((const char*)&node_idx, sizeof(int));
fout.write((const char*)&field[i*3], sizeof(Float)*3);
}
} else {
for (size_t i=0; i<m_num_nodes; i++) {
int node_idx = i+1;
fout << node_idx
<< " " << field[i*3]
<< " " << field[i*3+1]
<< " " << field[i*3+2]
<< std::endl;
}
}
fout << "$EndNodeData" << std::endl;
fout.flush();
}
IGL_INLINE void igl::MshSaver::save_elem_scalar_field(const std::string& fieldname, const FloatVector& field) {
assert(field.size() == m_num_elements);
fout << "$ElementData" << std::endl;
fout << 1 << std::endl; // num string tags.
fout << "\"" << fieldname << "\"" << std::endl;
fout << "1" << std::endl; // num real tags.
fout << "0.0" << std::endl; // time value.
fout << "3" << std::endl; // num int tags.
fout << "0" << std::endl; // the time step
fout << "1" << std::endl; // 1-component scalar field.
fout << m_num_elements << std::endl; // number of elements
if (m_binary) {
for (size_t i=0; i<m_num_elements; i++) {
int elem_idx = i+1;
fout.write((const char*)&elem_idx, sizeof(int));
fout.write((const char*)&field[i], sizeof(Float));
}
} else {
for (size_t i=0; i<m_num_elements; i++) {
int elem_idx = i+1;
fout << elem_idx << " " << field[i] << std::endl;
}
}
fout << "$EndElementData" << std::endl;
fout.flush();
}
IGL_INLINE void igl::MshSaver::save_elem_vector_field(const std::string& fieldname, const FloatVector& field) {
assert(field.size() == m_num_elements * 3);
fout << "$ElementData" << std::endl;
fout << 1 << std::endl; // num string tags.
fout << "\"" << fieldname << "\"" << std::endl;
fout << "1" << std::endl; // num real tags.
fout << "0.0" << std::endl; // time value.
fout << "3" << std::endl; // num int tags.
fout << "0" << std::endl; // the time step
fout << "3" << std::endl; // 3-component vector field.
fout << m_num_elements << std::endl; // number of elements
if (m_binary) {
for (size_t i=0; i<m_num_elements; ++i) {
int elem_idx = i+1;
fout.write((const char*)&elem_idx, sizeof(int));
fout.write((const char*)&field[i*3], sizeof(Float) * 3);
}
} else {
for (size_t i=0; i<m_num_elements; ++i) {
int elem_idx = i+1;
fout << elem_idx
<< " " << field[i*3]
<< " " << field[i*3+1]
<< " " << field[i*3+2]
<< std::endl;
}
}
fout << "$EndElementData" << std::endl;
fout.flush();
}
IGL_INLINE void igl::MshSaver::save_elem_tensor_field(const std::string& fieldname, const FloatVector& field) {
assert(field.size() == m_num_elements * 3 * (3 + 1) / 2);
fout << "$ElementData" << std::endl;
fout << 1 << std::endl; // num string tags.
fout << "\"" << fieldname << "\"" << std::endl;
fout << "1" << std::endl; // num real tags.
fout << "0.0" << std::endl; // time value.
fout << "3" << std::endl; // num int tags.
fout << "0" << std::endl; // the time step
fout << "9" << std::endl; // 9-component tensor field.
fout << m_num_elements << std::endl; // number of elements
if (m_binary) {
for (size_t i=0; i<m_num_elements; i++) {
int elem_idx = i+1;
fout.write((char*)&elem_idx, sizeof(int));
//const VectorF& val = field.segment(i*6, 6);
const Float* val = &field[i*6];
Float tensor[9] = {
val[0], val[5], val[4],
val[5], val[1], val[3],
val[4], val[3], val[2] };
fout.write((char*)tensor, sizeof(Float) * 9);
}
} else {
for (size_t i=0; i<m_num_elements; i++) {
int elem_idx = i+1;
const Float* val = &field[i*6];
fout << elem_idx
<< " " << val[0]
<< " " << val[5]
<< " " << val[4]
<< " " << val[5]
<< " " << val[1]
<< " " << val[3]
<< " " << val[4]
<< " " << val[3]
<< " " << val[2]
<< std::endl;
}
}
fout << "$EndElementData" << std::endl;
fout.flush();
}

View File

@@ -0,0 +1,87 @@
// based on MSH writer from PyMesh
// Copyright (c) 2015 Qingnan Zhou <qzhou@adobe.com>
// Copyright (C) 2020 Vladimir Fonov <vladimir.fonov@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_MSH_SAVER_H
#define IGL_MSH_SAVER_H
#include "igl_inline.h"
#include <fstream>
#include <string>
#include <vector>
namespace igl {
/// Class for dumping information to .msh file
/// depends only on c++stl library
/// current implementation works only with 3D information
class MshSaver {
public:
typedef double Float;
typedef std::vector<int> IndexVector;
typedef std::vector<int> IntVector;
typedef std::vector<Float> FloatVector;
typedef std::vector<FloatVector> FloatField;
typedef std::vector<IntVector> IntField;
typedef std::vector<std::string> FieldNames;
/// Write a .msh to a given path
/// @param[in] filename path to output file
/// @param[in] binary whether to write in binary format
MshSaver(const std::string& filename, bool binary=true);
~MshSaver();
public:
// Only these element types are supported right now
enum {ELEMENT_LINE=1, ELEMENT_TRI=2, ELEMENT_QUAD=3,
ELEMENT_TET=4, ELEMENT_HEX=5, ELEMENT_PRISM=6 };
public:
// save mesh geometry
void save_mesh(
const FloatVector& nodes,
const IndexVector& elements,
const IntVector& element_lengths,
const IntVector& element_type,
const IntVector& element_tags );
// save additional fields associated with the mesh
// add node scalar field
void save_scalar_field(const std::string& fieldname, const FloatVector& field);
// add node vectot field
void save_vector_field(const std::string& fieldname, const FloatVector& field);
// add element scalar field
void save_elem_scalar_field(const std::string& fieldname, const FloatVector& field);
// add element vector field
void save_elem_vector_field(const std::string& fieldname, const FloatVector& field);
// add element tensor field
void save_elem_tensor_field(const std::string& fieldname, const FloatVector& field);
protected:
void save_header();
void save_nodes(const FloatVector& nodes);
void save_elements(const IndexVector& elements,
const IntVector& element_lengths,
const IntVector& element_type,
const IntVector& element_tags);
private:
bool m_binary;
size_t m_num_nodes;
size_t m_num_elements;
std::ofstream fout;
};
} //igl
#ifndef IGL_STATIC_LIBRARY
# include "MshSaver.cpp"
#endif
#endif //MSH_SAVER_H

View File

@@ -10,14 +10,15 @@
namespace igl
{
// PER_VERTEX_NORMALS Normals computed per vertex based on incident faces
// PER_FACE_NORMALS Normals computed per face
// PER_CORNER_NORMALS Normals computed per corner (aka wedge) based on
// incident faces without sharp edge
/// Type of mesh normal computation method
enum NormalType
{
/// Normals computed per vertex based on incident faces
PER_VERTEX_NORMALS,
/// Normals computed per face
PER_FACE_NORMALS,
/// Normals computed per corner (aka wedge) based on incident faces without
/// sharp edge
PER_CORNER_NORMALS
};
# define NUM_NORMAL_TYPE 3

View File

@@ -9,9 +9,9 @@
#define IGL_ONE_H
namespace igl
{
// Often one needs a reference to a dummy variable containing one as its
// value, for example when using AntTweakBar's
// TwSetParam( "3D View", "opened", TW_PARAM_INT32, 1, &INT_ONE);
/// Often one needs a reference to a dummy variable containing one as its
/// value, for example when using AntTweakBar's
/// TwSetParam( "3D View", "opened", TW_PARAM_INT32, 1, &INT_ONE);
const char CHAR_ONE = 1;
const int INT_ONE = 1;
const unsigned int UNSIGNED_INT_ONE = 1;

View File

@@ -11,9 +11,11 @@ namespace igl
{
// Use standard mathematical constants' M_PI if available
#ifdef M_PI
const double PI = M_PI;
/// π
constexpr double PI = M_PI;
#else
const double PI = 3.1415926535897932384626433832795;
/// π
constexpr double PI = 3.1415926535897932384626433832795;
#endif
}
#endif

View File

@@ -0,0 +1,95 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2024 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_PLAINMATRIX_H
#define IGL_PLAINMATRIX_H
#include <Eigen/Core>
#include <type_traits>
#include <Eigen/Dense>
// Define void_t for compatibility if it's not in the standard library (C++11 and later)
#if __cplusplus < 201703L
namespace std {
template <typename... Ts>
using void_t = void;
}
#endif
#ifndef IGL_DEFAULT_MAJORING
#define IGL_DEFAULT_MAJORING Eigen::ColMajor
#endif
namespace igl
{
template <typename Derived, int Rows, int Cols, int Options>
struct PlainMatrixHelper {
using Type = Eigen::Matrix<typename Derived::Scalar,Rows,Cols,((Rows == 1 && Cols != 1) ? Eigen::RowMajor : ((Cols == 1 && Rows != 1) ? Eigen::ColMajor : Options))>;
};
template <typename Derived, typename = void>
struct get_options {
static constexpr int value = IGL_DEFAULT_MAJORING;
};
template <typename Derived>
struct get_options<Derived, std::void_t<decltype(Derived::Options)>> {
static constexpr int value = Derived::Options;
};
/// Some libigl implementations would (still do?) use a pattern like:
///
/// template <typename DerivedA>
/// void foo(const Eigen::MatrixBase<DerivedA>& A)
/// {
/// DerivedA B;
/// igl::unique_rows(A,true,B);
/// }
///
/// If `DerivedA` is `Eigen::Matrix`, then this may compile, but `DerivedA` might be
/// from a Eigen::Map or Eigen::Ref and fail to compile due to missing
/// construtor.
///
/// Even worse, the code above will work if `DerivedA` has dynamic rows, but will
/// throw a runtime error if `DerivedA` has fixed number of rows.
///
/// Instead it's better to declare `B` as a `Eigen::Matrix`
///
/// Eigen::Matrix<typename DerivedA::Scalar,Eigen::Dynamic,DerivedA::ColsAtCompileTime,DerivedA::Options> B;
///
/// Using `Eigen::Dynamic` for dimensions that may not be known at compile
/// time (or may be different from A).
///
/// `igl::PlainMatrix` is just a helper to make this easier. So in this case
/// we could write:
///
/// igl::PlainMatrix<DerivedA,Eigen::Dynamic> B;
///
/// IIUC, if the code in question looks like:
///
/// template <typename DerivedC>
/// void foo(Eigen::PlainObjectBase<DerivedC>& C)
/// {
/// DerivedC B;
/// …
/// C.resize(not_known_at_compile_time,also_not_known_at_compile_time);
/// }
///
/// Then it's probably fine. If C can be resized to different sizes, then
/// `DerivedC` should be `Eigen::Matrix`-like .
// Helper to check if `Options` exists in Derived
// Modify PlainMatrix to use get_options
template <typename Derived,
int Rows = Derived::RowsAtCompileTime,
int Cols = Derived::ColsAtCompileTime,
int Options = get_options<Derived>::value>
using PlainMatrix = typename PlainMatrixHelper<Derived, Rows, Cols, Options>::Type;
}
#endif

View File

@@ -0,0 +1,36 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2024 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_PLAINVECTOR_H
#define IGL_PLAINVECTOR_H
#include <Eigen/Core>
#include "PlainMatrix.h"
namespace igl
{
// PlainVectorHelper to determine correct matrix type based on Derived and Size
template <typename Derived, int Size, int Options>
struct PlainVectorHelper {
// Conditional Type: Column vector if is_column_vector is true, otherwise row vector
using Type = Eigen::Matrix<
typename Derived::Scalar,
(Derived::ColsAtCompileTime == 1 && Derived::RowsAtCompileTime != 1) ? Size : 1,
(Derived::ColsAtCompileTime == 1 && Derived::RowsAtCompileTime != 1) ? 1 : Size,
Options>;
};
/// \see PlainMatrix
template <
typename Derived,
int Size = (Derived::ColsAtCompileTime == 1 && Derived::RowsAtCompileTime != 1) ? Derived::RowsAtCompileTime : Derived::ColsAtCompileTime,
int Options = get_options<Derived>::value>
using PlainVector = typename PlainVectorHelper<Derived, Size, Options>::Type;
}
#endif

View File

@@ -35,9 +35,17 @@
#else
/// Bold red colored text
/// @param[in] X text to color
/// @returns colored text as "stream"
/// #### Example:
///
/// \code{cpp}
/// std::cout<<REDRUM("File "<<filename<<" not found.")<<std::endl;
/// \endcode
#define REDRUM(X) "\e[1m\e[31m"<<X<<"\e[m"
// Bold Red, etc.
#define NORUM(X) ""<<X<<""
#define REDRUM(X) "\e[1m\e[31m"<<X<<"\e[m"
#define GREENRUM(X) "\e[1m\e[32m"<<X<<"\e[m"
#define YELLOWRUM(X) "\e[1m\e[33m"<<X<<"\e[m"
#define BLUERUM(X) "\e[1m\e[34m"<<X<<"\e[m"

View File

@@ -7,12 +7,23 @@
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_STR_H
#define IGL_STR_H
// http://stackoverflow.com/a/2433143/148668
#include <string>
#include <sstream>
// Suppose you have a function:
// void func(std::string c);
// Then you can write:
// func(STR("foo"<<1<<"bar"));
/// Convert a stream of things to std:;string
///
/// Suppose you have a function:
/// \code{cpp}
/// void func(std::string s);
/// \endcode
/// Then you can write:
/// \code{cpp}
/// func(C_STR("foo"<<1<<"bar"));
/// \endcode
/// which is equivalent to:
/// \code{cpp}
/// func("foo1bar");
/// \endcode
///
// http://stackoverflow.com/a/2433143/148668
#define STR(X) static_cast<std::ostringstream&>(std::ostringstream().flush() << X).str()
#endif

View File

@@ -18,6 +18,9 @@
#pragma warning( disable : 592 )
#endif
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wuninitialized"
// #define USE_ACCURATE_RSQRT_IN_JACOBI_CONJUGATION
// #define PERFORM_STRICT_QUATERNION_RENORMALIZATION
@@ -1272,6 +1275,8 @@
#endif
#endif
#pragma clang diagnostic pop
#ifdef __INTEL_COMPILER
#pragma warning( default : 592 )
#endif

View File

@@ -9,14 +9,16 @@
#define IGL_SOLVER_STATUS_H
namespace igl
{
/// Solver status type used by min_quad_with_fixed
enum SolverStatus
{
// Good
// Good. Solver declared convergence
SOLVER_STATUS_CONVERGED = 0,
// OK
// OK. Solver reached max iterations
SOLVER_STATUS_MAX_ITER = 1,
// Bad
// Bad. Solver reported failure
SOLVER_STATUS_ERROR = 2,
// Total number of solver types
NUM_SOLVER_STATUSES = 3,
};
};

View File

@@ -1,9 +1,9 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.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_SORTABLE_ROW_H
#define IGL_SORTABLE_ROW_H
@@ -14,53 +14,66 @@
namespace igl
{
// Templates:
// T should be a matrix that implements .size(), and operator(int i)
template <typename T>
class SortableRow
{
public:
T data;
public:
SortableRow():data(){};
SortableRow(const T & data):data(data){};
bool operator<(const SortableRow & that) const
{
/// A row of things that can be sorted against other rows
/// @tparam T should be a vector/matrix/array that implements .size(), and operator(int i)
template <typename T>
class SortableRow
{
public:
/// The data
T data;
public:
/// Default constructor
SortableRow():data(){};
/// Constructor
/// @param[in] data the data
SortableRow(const T & data):data(data){};
/// Less than comparison
/// @param[in] that the other row
/// @returns true if this row is less than that row
bool operator<(const SortableRow & that) const
{
// Lexicographical
int minc = (this->data.size() < that.data.size()?
this->data.size() : that.data.size());
this->data.size() : that.data.size());
// loop over columns
for(int i = 0;i<minc;i++)
{
if(this->data(i) == that.data(i))
{
continue;
}
return this->data(i) < that.data(i);
if(this->data(i) == that.data(i))
{
continue;
}
return this->data(i) < that.data(i);
}
// All characters the same, comes done to length
return this->data.size()<that.data.size();
};
bool operator==(const SortableRow & that) const
{
};
/// Equality comparison
/// @param[in] that the other row
/// @returns true if this row is equal to that row
bool operator==(const SortableRow & that) const
{
if(this->data.size() != that.data.size())
{
return false;
return false;
}
for(int i = 0;i<this->data.size();i++)
{
if(this->data(i) != that.data(i))
{
return false;
}
if(this->data(i) != that.data(i))
{
return false;
}
}
return true;
};
bool operator!=(const SortableRow & that) const
{
};
/// Inequality comparison
/// @param[in] that the other row
/// @returns true if this row is not equal to that row
bool operator!=(const SortableRow & that) const
{
return !(*this == that);
};
};
};
};
}
#endif

View File

@@ -22,13 +22,15 @@
#include <sys/time.h>
#endif
#include <cstddef>
#include <cstdint>
namespace igl
{
/// Simple timer class
class Timer
{
public:
// default constructor
/// default constructor
Timer():
stopped(0),
#ifdef WIN32
@@ -64,10 +66,13 @@ namespace igl
}
#ifdef __APPLE__
//Raw mach_absolute_times going in, difference in seconds out
double subtractTimes( uint64_t endTime, uint64_t startTime )
/// Raw mach_absolute_times going in, difference in seconds out
/// @param[in] endTime end time
/// @param[in] startTime start time
/// @return time
double subtractTimes( std::uint64_t endTime, std::uint64_t startTime )
{
uint64_t difference = endTime - startTime;
std::uint64_t difference = endTime - startTime;
static double conversion = 0.0;
if( conversion == 0.0 )
@@ -84,7 +89,7 @@ namespace igl
}
#endif
// start timer
/// start timer
void start()
{
stopped = 0; // reset stop flag
@@ -98,7 +103,7 @@ namespace igl
}
// stop the timer
/// stop the timer
void stop()
{
stopped = 1; // set timer stopped flag
@@ -112,23 +117,27 @@ namespace igl
#endif
}
// get elapsed time in second
/// get elapsed time in second
/// @return time in seconds
double getElapsedTime()
{
return this->getElapsedTimeInSec();
}
// get elapsed time in second (same as getElapsedTime)
/// get elapsed time in second (same as getElapsedTime)
/// @return time
double getElapsedTimeInSec()
{
return this->getElapsedTimeInMicroSec() * 0.000001;
}
// get elapsed time in milli-second
/// get elapsed time in milli-second
/// @return time
double getElapsedTimeInMilliSec()
{
return this->getElapsedTimeInMicroSec() * 0.001;
}
// get elapsed time in micro-second
/// get elapsed time in micro-second
/// @return time
double getElapsedTimeInMicroSec()
{
double startTimeInMicroSec = 0;
@@ -167,8 +176,8 @@ namespace igl
LARGE_INTEGER startCount;
LARGE_INTEGER endCount;
#elif __APPLE__
uint64_t startCount;
uint64_t endCount;
std::uint64_t startCount;
std::uint64_t endCount;
#else
timeval startCount;
timeval endCount;

View File

@@ -10,6 +10,7 @@
namespace igl
{
/// @private
// Simple Viewport class for an opengl context. Handles reshaping and mouse.
struct Viewport
{

View File

@@ -13,19 +13,24 @@
#ifndef IGL_WINDINGNUMBERAABB_H
#define IGL_WINDINGNUMBERAABB_H
#include "WindingNumberTree.h"
#include "PlainMatrix.h"
namespace igl
{
/// Class for building an AABB tree to implement the divide and conquer
/// algorithm described in [Jacobson et al. 2013].
template <
typename Point,
typename DerivedV,
typename DerivedF >
class WindingNumberAABB : public WindingNumberTree<Point,DerivedV,DerivedF>
typename Scalar,
typename Index>
class WindingNumberAABB : public WindingNumberTree<Scalar,Index>
{
protected:
// WindingNumberTree defines Point
using Point = typename WindingNumberTree<Scalar,Index>::Point;
using MatrixXF = typename WindingNumberTree<Scalar,Index>::MatrixXF;
Point min_corner;
Point max_corner;
typename DerivedV::Scalar total_positive_area;
Scalar total_positive_area;
public:
enum SplitMethod
{
@@ -35,16 +40,25 @@ namespace igl
} split_method;
public:
inline WindingNumberAABB():
total_positive_area(std::numeric_limits<typename DerivedV::Scalar>::infinity()),
total_positive_area(std::numeric_limits<Scalar>::infinity()),
split_method(MEDIAN_ON_LONGEST_AXIS)
{}
/// Constructor
///
/// @param[in] V #V by 3 list of vertex positions
/// @param[in] F #F by 3 list of triangle indices into V
template <typename DerivedV, typename DerivedF>
inline WindingNumberAABB(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F);
inline WindingNumberAABB(
const WindingNumberTree<Point,DerivedV,DerivedF> & parent,
const Eigen::MatrixBase<DerivedF> & F);
// Initialize some things
const WindingNumberTree<Scalar,Index> & parent,
const typename WindingNumberTree<Scalar,Index>::MatrixXF & F);
/// Initialize the hierarchy to a given mesh
///
/// @param[in] V #V by 3 list of vertex positions
/// @param[in] F #F by 3 list of triangle indices into V
template <typename DerivedV, typename DerivedF>
inline void set_mesh(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F);
@@ -53,8 +67,8 @@ namespace igl
inline virtual void grow();
// Compute min and max corners
inline void compute_min_max_corners();
inline typename DerivedV::Scalar max_abs_winding_number(const Point & p) const;
inline typename DerivedV::Scalar max_simple_abs_winding_number(const Point & p) const;
inline Scalar max_abs_winding_number(const Point & p) const;
inline Scalar max_simple_abs_winding_number(const Point & p) const;
};
}
@@ -77,70 +91,76 @@ namespace igl
# define WindingNumberAABB_MIN_F 100
#endif
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::set_mesh(
template <typename Scalar, typename Index>
template <typename DerivedV, typename DerivedF>
inline void igl::WindingNumberAABB<Scalar,Index>::set_mesh(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F)
{
igl::WindingNumberTree<Point,DerivedV,DerivedF>::set_mesh(V,F);
// static assert that DerivedF::ColsAtCompileTime == 3 or Eigen::Dynamic
static_assert(
DerivedF::ColsAtCompileTime == 3 || DerivedF::ColsAtCompileTime == Eigen::Dynamic,
"F should have 3 or Dynamic columns");
igl::WindingNumberTree<Scalar,Index>::set_mesh(V,F);
init();
}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::init()
template <typename Scalar, typename Index>
inline void igl::WindingNumberAABB<Scalar,Index>::init()
{
using namespace Eigen;
assert(max_corner.size() == 3);
assert(min_corner.size() == 3);
compute_min_max_corners();
Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,1> dblA;
doublearea(this->getV(),this->getF(),dblA);
Eigen::Matrix<Scalar,Eigen::Dynamic,1> dblA;
doublearea((*this->Vptr),(this->F),dblA);
total_positive_area = dblA.sum()/2.0;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline igl::WindingNumberAABB<Point,DerivedV,DerivedF>::WindingNumberAABB(
template <typename Scalar, typename Index>
template <typename DerivedV, typename DerivedF>
inline igl::WindingNumberAABB<Scalar,Index>::WindingNumberAABB(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F):
WindingNumberTree<Point,DerivedV,DerivedF>(V,F),
WindingNumberTree<Scalar,Index>(V,F),
min_corner(),
max_corner(),
total_positive_area(
std::numeric_limits<typename DerivedV::Scalar>::infinity()),
std::numeric_limits<Scalar>::infinity()),
split_method(MEDIAN_ON_LONGEST_AXIS)
{
init();
}
template <typename Point, typename DerivedV, typename DerivedF>
inline igl::WindingNumberAABB<Point,DerivedV,DerivedF>::WindingNumberAABB(
const WindingNumberTree<Point,DerivedV,DerivedF> & parent,
const Eigen::MatrixBase<DerivedF> & F):
WindingNumberTree<Point,DerivedV,DerivedF>(parent,F),
template <typename Scalar, typename Index>
inline igl::WindingNumberAABB<Scalar,Index>::WindingNumberAABB(
const WindingNumberTree<Scalar,Index> & parent,
const typename WindingNumberTree<Scalar,Index>::MatrixXF & F):
WindingNumberTree<Scalar,Index>(parent,F),
min_corner(),
max_corner(),
total_positive_area(
std::numeric_limits<typename DerivedV::Scalar>::infinity()),
std::numeric_limits<Scalar>::infinity()),
split_method(MEDIAN_ON_LONGEST_AXIS)
{
init();
}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::grow()
template <typename Scalar, typename Index>
inline void igl::WindingNumberAABB<Scalar,Index>::grow()
{
using namespace std;
using namespace Eigen;
// Clear anything that already exists
this->delete_children();
//cout<<"cap.rows(): "<<this->getcap().rows()<<endl;
//cout<<"F.rows(): "<<this->getF().rows()<<endl;
//cout<<"cap.rows(): "<<(this->cap).rows()<<endl;
//cout<<"F.rows(): "<<(this->F).rows()<<endl;
// Base cases
if(
this->getF().rows() <= (WindingNumberAABB_MIN_F>0?WindingNumberAABB_MIN_F:0) ||
(this->getcap().rows() - 2) >= this->getF().rows())
(this->F).rows() <= (WindingNumberAABB_MIN_F>0?WindingNumberAABB_MIN_F:0) ||
((this->cap).rows() - 2) >= (this->F).rows())
{
// Don't grow
return;
@@ -148,8 +168,8 @@ inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::grow()
// Compute longest direction
int max_d = -1;
typename DerivedV::Scalar max_len =
-numeric_limits<typename DerivedV::Scalar>::infinity();
Scalar max_len =
-numeric_limits<Scalar>::infinity();
for(int d = 0;d<min_corner.size();d++)
{
if( (max_corner[d] - min_corner[d]) > max_len )
@@ -159,13 +179,13 @@ inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::grow()
}
}
// Compute facet barycenters
Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,Eigen::Dynamic> BC;
barycenter(this->getV(),this->getF(),BC);
Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> BC;
barycenter((*this->Vptr),(this->F),BC);
// Blerg, why is selecting rows so difficult
typename DerivedV::Scalar split_value;
Scalar split_value;
// Split in longest direction
switch(split_method)
{
@@ -182,8 +202,8 @@ inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::grow()
//cout<<"c: "<<0.5*(max_corner[max_d] + min_corner[max_d])<<" "<<
// "m: "<<split_value<<endl;;
vector<int> id( this->getF().rows());
for(int i = 0;i<this->getF().rows();i++)
vector<int> id( (this->F).rows());
for(int i = 0;i<(this->F).rows();i++)
{
if(BC(i,max_d) <= split_value)
{
@@ -201,19 +221,19 @@ inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::grow()
// badly balanced base case (could try to recut)
return;
}
assert(lefts+rights == this->getF().rows());
DerivedF leftF(lefts, this->getF().cols());
DerivedF rightF(rights,this->getF().cols());
assert(lefts+rights == (this->F).rows());
MatrixXF leftF(lefts, (this->F).cols());
MatrixXF rightF(rights,(this->F).cols());
int left_i = 0;
int right_i = 0;
for(int i = 0;i<this->getF().rows();i++)
for(int i = 0;i<(this->F).rows();i++)
{
if(id[i] == 0)
{
leftF.row(left_i++) = this->getF().row(i);
leftF.row(left_i++) = (this->F).row(i);
}else if(id[i] == 1)
{
rightF.row(right_i++) = this->getF().row(i);
rightF.row(right_i++) = (this->F).row(i);
}else
{
assert(false);
@@ -222,18 +242,18 @@ inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::grow()
assert(right_i == rightF.rows());
assert(left_i == leftF.rows());
// Finally actually grow children and Recursively grow
WindingNumberAABB<Point,DerivedV,DerivedF> * leftWindingNumberAABB =
new WindingNumberAABB<Point,DerivedV,DerivedF>(*this,leftF);
WindingNumberAABB<Scalar,Index> * leftWindingNumberAABB =
new WindingNumberAABB<Scalar,Index>(*this,leftF);
leftWindingNumberAABB->grow();
this->children.push_back(leftWindingNumberAABB);
WindingNumberAABB<Point,DerivedV,DerivedF> * rightWindingNumberAABB =
new WindingNumberAABB<Point,DerivedV,DerivedF>(*this,rightF);
WindingNumberAABB<Scalar,Index> * rightWindingNumberAABB =
new WindingNumberAABB<Scalar,Index>(*this,rightF);
rightWindingNumberAABB->grow();
this->children.push_back(rightWindingNumberAABB);
}
template <typename Point, typename DerivedV, typename DerivedF>
inline bool igl::WindingNumberAABB<Point,DerivedV,DerivedF>::inside(const Point & p) const
template <typename Scalar, typename Index>
inline bool igl::WindingNumberAABB<Scalar,Index>::inside(const Point & p) const
{
assert(p.size() == max_corner.size());
assert(p.size() == min_corner.size());
@@ -250,8 +270,8 @@ inline bool igl::WindingNumberAABB<Point,DerivedV,DerivedF>::inside(const Point
return true;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::compute_min_max_corners()
template <typename Scalar, typename Index>
inline void igl::WindingNumberAABB<Scalar,Index>::compute_min_max_corners()
{
using namespace std;
// initialize corners
@@ -263,26 +283,26 @@ inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::compute_min_max_cor
this->center = Point(0,0,0);
// Loop over facets
for(int i = 0;i<this->getF().rows();i++)
for(int i = 0;i<(this->F).rows();i++)
{
for(int j = 0;j<this->getF().cols();j++)
for(int j = 0;j<(this->F).cols();j++)
{
for(int d = 0;d<min_corner.size();d++)
{
min_corner[d] =
this->getV()(this->getF()(i,j),d) < min_corner[d] ?
this->getV()(this->getF()(i,j),d) : min_corner[d];
(*this->Vptr)((this->F)(i,j),d) < min_corner[d] ?
(*this->Vptr)((this->F)(i,j),d) : min_corner[d];
max_corner[d] =
this->getV()(this->getF()(i,j),d) > max_corner[d] ?
this->getV()(this->getF()(i,j),d) : max_corner[d];
(*this->Vptr)((this->F)(i,j),d) > max_corner[d] ?
(*this->Vptr)((this->F)(i,j),d) : max_corner[d];
}
// This is biased toward vertices incident on more than one face, but
// perhaps that's good
this->center += this->getV().row(this->getF()(i,j));
this->center += (*this->Vptr).row((this->F)(i,j));
}
}
// Average
this->center.array() /= this->getF().size();
this->center.array() /= (this->F).size();
//cout<<"min_corner: "<<this->min_corner.transpose()<<endl;
//cout<<"Center: "<<this->center.transpose()<<endl;
@@ -293,24 +313,24 @@ inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::compute_min_max_cor
this->radius = (max_corner-min_corner).norm()/2.0;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberAABB<Point,DerivedV,DerivedF>::max_abs_winding_number(const Point & p) const
template <typename Scalar, typename Index>
inline Scalar
igl::WindingNumberAABB<Scalar,Index>::max_abs_winding_number(const Point & p) const
{
using namespace std;
// Only valid if not inside
if(inside(p))
{
return numeric_limits<typename DerivedV::Scalar>::infinity();
return numeric_limits<Scalar>::infinity();
}
// Q: we know the total positive area so what's the most this could project
// to? Remember it could be layered in the same direction.
return numeric_limits<typename DerivedV::Scalar>::infinity();
return numeric_limits<Scalar>::infinity();
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberAABB<Point,DerivedV,DerivedF>::max_simple_abs_winding_number(
template <typename Scalar, typename Index>
inline Scalar
igl::WindingNumberAABB<Scalar,Index>::max_simple_abs_winding_number(
const Point & p) const
{
using namespace std;
@@ -318,7 +338,7 @@ inline typename DerivedV::Scalar
// Only valid if not inside
if(inside(p))
{
return numeric_limits<typename DerivedV::Scalar>::infinity();
return numeric_limits<Scalar>::infinity();
}
// Max simple is the same as sum of positive winding number contributions of
// bounding box
@@ -326,10 +346,10 @@ inline typename DerivedV::Scalar
// begin precomputation
//MatrixXd BV((int)pow(2,3),3);
typedef
Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,Eigen::Dynamic>
Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>
MatrixXS;
typedef
Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,Eigen::Dynamic>
Eigen::Matrix<Index,Eigen::Dynamic,Eigen::Dynamic>
MatrixXF;
MatrixXS BV((int)(1<<3),3);
BV <<

View File

@@ -9,14 +9,15 @@
#define IGL_WINDINGNUMBERMETHOD_H
namespace igl
{
// EXACT_WINDING_NUMBER_METHOD exact hierarchical evaluation
// APPROX_SIMPLE_WINDING_NUMBER_METHOD poor approximation
// APPROX_CACHE_WINDING_NUMBER_METHOD another poor approximation
enum WindingNumberMethod
{
// exact hierarchical evaluation
EXACT_WINDING_NUMBER_METHOD = 0,
// poor approximation
APPROX_SIMPLE_WINDING_NUMBER_METHOD = 1,
// another poor approximation
APPROX_CACHE_WINDING_NUMBER_METHOD = 2,
/// Number of winding number methods
NUM_WINDING_NUMBER_METHODS = 3
};
}

View File

@@ -11,74 +11,67 @@
#include <map>
#include <Eigen/Dense>
#include "WindingNumberMethod.h"
#include <memory>
namespace igl
{
// Space partitioning tree for computing winding number hierarchically.
//
// Templates:
// Point type for points in space, e.g. Eigen::Vector3d
/// Space partitioning tree for computing winding number hierarchically.
template <
typename Point,
typename DerivedV,
typename DerivedF >
typename Scalar,
typename Index>
class WindingNumberTree
{
public:
using Point = Eigen::Matrix<Scalar,1,3>;
// Method to use (see enum above)
//static double min_max_w;
static std::map<
std::pair<const WindingNumberTree*,const WindingNumberTree*>,
typename DerivedV::Scalar>
Scalar>
cached;
// This is only need to fill in references, it should never actually be touched
// and shouldn't cause race conditions. (This is a hack, but I think it's "safe")
static DerivedV dummyV;
protected:
WindingNumberMethod method;
const WindingNumberTree * parent;
std::list<WindingNumberTree * > children;
typedef
Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,Eigen::Dynamic>
Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>
MatrixXS;
typedef
Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,Eigen::Dynamic>
Eigen::Matrix<Index,Eigen::Dynamic,Eigen::Dynamic>
MatrixXF;
//// List of boundary edges (recall edges are vertices in 2d)
//const Eigen::MatrixXi boundary;
// Base mesh vertices
DerivedV & V;
// Base mesh vertices with duplicates removed
// Base mesh vertices with duplicates removed (root will fill this in and
// then everyone's Vptr will point to it.
MatrixXS SV;
// Shared pointer to base mesh vertices
std::shared_ptr<MatrixXS> Vptr;
// Facets in this bounding volume
MatrixXF F;
// Tessellated boundary curve
MatrixXF cap;
// Upper Bound on radius of enclosing ball
typename DerivedV::Scalar radius;
Scalar radius;
// (Approximate) center (of mass)
Point center;
public:
inline WindingNumberTree();
// For root
template <typename DerivedV, typename DerivedF>
inline WindingNumberTree(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F);
// For chilluns
inline WindingNumberTree(
const WindingNumberTree<Point,DerivedV,DerivedF> & parent,
const Eigen::MatrixBase<DerivedF> & F);
const WindingNumberTree<Scalar,Index> & parent,
const typename igl::WindingNumberTree<Scalar,Index>::MatrixXF & F);
inline virtual ~WindingNumberTree();
inline void delete_children();
inline virtual void set_mesh(
template <typename DerivedV, typename DerivedF>
inline void set_mesh(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F);
// Set method
inline void set_method( const WindingNumberMethod & m);
public:
inline const DerivedV & getV() const;
inline const MatrixXF & getF() const;
inline const MatrixXF & getcap() const;
// Grow the Tree recursively
inline virtual void grow();
// Determine whether a given point is inside the bounding
@@ -93,12 +86,12 @@ namespace igl
// Inputs:
// p query point
// Returns winding number
inline typename DerivedV::Scalar winding_number(const Point & p) const;
inline Scalar winding_number(const Point & p) const;
// Same as above, but always computes winding number using exact method
// (sum over every facet)
inline typename DerivedV::Scalar winding_number_all(const Point & p) const;
inline Scalar winding_number_all(const Point & p) const;
// Same as above, but always computes using sum over tessllated boundary
inline typename DerivedV::Scalar winding_number_boundary(const Point & p) const;
inline Scalar winding_number_boundary(const Point & p) const;
//// Same as winding_number above, but if max_simple_abs_winding_number is
//// less than some threshold min_max_w just return 0 (colloquially the "fast
//// multipole method)
@@ -121,10 +114,10 @@ namespace igl
// Inputs:
// p query point
// Returns max winding number of
inline virtual typename DerivedV::Scalar max_abs_winding_number(const Point & p) const;
inline virtual Scalar max_abs_winding_number(const Point & p) const;
// Same as above, but stronger assumptions on (V,F). Assumes (V,F) is a
// simple polyhedron
inline virtual typename DerivedV::Scalar max_simple_abs_winding_number(const Point & p) const;
inline virtual Scalar max_simple_abs_winding_number(const Point & p) const;
// Compute or read cached winding number for point p with respect to mesh
// in bounding box, recursing according to approximation criteria
//
@@ -132,7 +125,7 @@ namespace igl
// p query point
// that WindingNumberTree containing mesh w.r.t. which we're computing w.n.
// Returns cached winding number
inline virtual typename DerivedV::Scalar cached_winding_number(const WindingNumberTree & that, const Point & p) const;
inline virtual Scalar cached_winding_number(const WindingNumberTree & that, const Point & p) const;
};
}
@@ -143,53 +136,51 @@ namespace igl
#include "triangle_fan.h"
#include "exterior_edges.h"
#include <igl/PI.h>
#include <igl/remove_duplicate_vertices.h>
#include "PI.h"
#include "remove_duplicate_vertices.h"
#include <iostream>
#include <limits>
//template <typename Point, typename DerivedV, typename DerivedF>
//WindingNumberMethod WindingNumberTree<Point,DerivedV,DerivedF>::method = EXACT_WINDING_NUMBER_METHOD;
//template <typename Point, typename DerivedV, typename DerivedF>
//double WindingNumberTree<Point,DerivedV,DerivedF>::min_max_w = 0;
template <typename Point, typename DerivedV, typename DerivedF>
std::map< std::pair<const igl::WindingNumberTree<Point,DerivedV,DerivedF>*,const igl::WindingNumberTree<Point,DerivedV,DerivedF>*>, typename DerivedV::Scalar>
igl::WindingNumberTree<Point,DerivedV,DerivedF>::cached;
//template <typename Scalar, typename Index>
//WindingNumberMethod WindingNumberTree<Scalar,Index>::method = EXACT_WINDING_NUMBER_METHOD;
//template <typename Scalar, typename Index>
//double WindingNumberTree<Scalar,Index>::min_max_w = 0;
template <typename Scalar, typename Index>
std::map< std::pair<const igl::WindingNumberTree<Scalar,Index>*,const igl::WindingNumberTree<Scalar,Index>*>, Scalar>
igl::WindingNumberTree<Scalar,Index>::cached;
template <typename Point, typename DerivedV, typename DerivedF>
inline igl::WindingNumberTree<Point,DerivedV,DerivedF>::WindingNumberTree():
template <typename Scalar, typename Index>
inline igl::WindingNumberTree<Scalar,Index>::WindingNumberTree():
method(EXACT_WINDING_NUMBER_METHOD),
parent(NULL),
V(dummyV),
SV(),
F(),
//boundary(igl::boundary_facets<Eigen::MatrixXi,Eigen::MatrixXi>(F))
cap(),
radius(std::numeric_limits<typename DerivedV::Scalar>::infinity()),
radius(std::numeric_limits<Scalar>::infinity()),
center(0,0,0)
{
}
template <typename Point, typename DerivedV, typename DerivedF>
inline igl::WindingNumberTree<Point,DerivedV,DerivedF>::WindingNumberTree(
template <typename Scalar, typename Index>
template <typename DerivedV, typename DerivedF>
inline igl::WindingNumberTree<Scalar,Index>::WindingNumberTree(
const Eigen::MatrixBase<DerivedV> & _V,
const Eigen::MatrixBase<DerivedF> & _F):
method(EXACT_WINDING_NUMBER_METHOD),
parent(NULL),
V(dummyV),
SV(),
F(),
//boundary(igl::boundary_facets<Eigen::MatrixXi,Eigen::MatrixXi>(F))
cap(),
radius(std::numeric_limits<typename DerivedV::Scalar>::infinity()),
radius(std::numeric_limits<Scalar>::infinity()),
center(0,0,0)
{
set_mesh(_V,_F);
}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::set_mesh(
template <typename Scalar, typename Index>
template <typename DerivedV, typename DerivedF>
inline void igl::WindingNumberTree<Scalar,Index>::set_mesh(
const Eigen::MatrixBase<DerivedV> & _V,
const Eigen::MatrixBase<DerivedF> & _F)
{
@@ -197,37 +188,45 @@ inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::set_mesh(
// Remove any exactly duplicate vertices
// Q: Can this ever increase the complexity of the boundary?
// Q: Would we gain even more by remove almost exactly duplicate vertices?
MatrixXF SF,SVI,SVJ;
Eigen::Matrix<typename MatrixXF::Scalar,Eigen::Dynamic,1> SVI,SVJ;
igl::remove_duplicate_vertices(_V,_F,0.0,SV,SVI,SVJ,F);
triangle_fan(igl::exterior_edges(F),cap);
V = SV;
{
Eigen::Matrix<typename MatrixXF::Scalar,Eigen::Dynamic,2> EE;
igl::exterior_edges(F,EE);
triangle_fan(EE,cap);
}
// point Vptr to SV
Vptr = std::make_shared<MatrixXS>(SV);
}
template <typename Point, typename DerivedV, typename DerivedF>
inline igl::WindingNumberTree<Point,DerivedV,DerivedF>::WindingNumberTree(
const igl::WindingNumberTree<Point,DerivedV,DerivedF> & parent,
const Eigen::MatrixBase<DerivedF> & _F):
template <typename Scalar, typename Index>
inline igl::WindingNumberTree<Scalar,Index>::WindingNumberTree(
const igl::WindingNumberTree<Scalar,Index> & parent,
const typename igl::WindingNumberTree<Scalar,Index>::MatrixXF & _F):
method(parent.method),
parent(&parent),
V(parent.V),
Vptr(parent.Vptr),
SV(),
F(_F),
cap(triangle_fan(igl::exterior_edges(_F)))
cap()
{
Eigen::Matrix<typename MatrixXF::Scalar,Eigen::Dynamic,2> EE;
igl::exterior_edges(F,EE);
triangle_fan(EE,cap);
}
template <typename Point, typename DerivedV, typename DerivedF>
inline igl::WindingNumberTree<Point,DerivedV,DerivedF>::~WindingNumberTree()
template <typename Scalar, typename Index>
inline igl::WindingNumberTree<Scalar,Index>::~WindingNumberTree()
{
delete_children();
}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::delete_children()
template <typename Scalar, typename Index>
inline void igl::WindingNumberTree<Scalar,Index>::delete_children()
{
using namespace std;
// Delete children
typename list<WindingNumberTree<Point,DerivedV,DerivedF>* >::iterator cit = children.begin();
typename list<WindingNumberTree<Scalar,Index>* >::iterator cit = children.begin();
while(cit != children.end())
{
// clear the memory of this item
@@ -237,8 +236,8 @@ inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::delete_children()
}
}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::set_method(const WindingNumberMethod & m)
template <typename Scalar, typename Index>
inline void igl::WindingNumberTree<Scalar,Index>::set_method(const WindingNumberMethod & m)
{
this->method = m;
for(auto child : children)
@@ -247,42 +246,22 @@ inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::set_method(const Wi
}
}
template <typename Point, typename DerivedV, typename DerivedF>
inline const DerivedV & igl::WindingNumberTree<Point,DerivedV,DerivedF>::getV() const
{
return V;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline const typename igl::WindingNumberTree<Point,DerivedV,DerivedF>::MatrixXF&
igl::WindingNumberTree<Point,DerivedV,DerivedF>::getF() const
{
return F;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline const typename igl::WindingNumberTree<Point,DerivedV,DerivedF>::MatrixXF&
igl::WindingNumberTree<Point,DerivedV,DerivedF>::getcap() const
{
return cap;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::grow()
template <typename Scalar, typename Index>
inline void igl::WindingNumberTree<Scalar,Index>::grow()
{
// Don't grow
return;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline bool igl::WindingNumberTree<Point,DerivedV,DerivedF>::inside(const Point & /*p*/) const
template <typename Scalar, typename Index>
inline bool igl::WindingNumberTree<Scalar,Index>::inside(const Point & /*p*/) const
{
return true;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number(const Point & p) const
template <typename Scalar, typename Index>
inline Scalar
igl::WindingNumberTree<Scalar,Index>::winding_number(const Point & p) const
{
using namespace std;
//cout<<"+"<<boundary.rows();
@@ -293,9 +272,9 @@ igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number(const Point & p)
if(children.size()>0)
{
// Recurse on each child and accumulate
typename DerivedV::Scalar sum = 0;
Scalar sum = 0;
for(
typename list<WindingNumberTree<Point,DerivedV,DerivedF>* >::const_iterator cit = children.begin();
typename list<WindingNumberTree<Scalar,Index>* >::const_iterator cit = children.begin();
cit != children.end();
cit++)
{
@@ -333,7 +312,7 @@ igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number(const Point & p)
return winding_number_boundary(p);
case APPROX_SIMPLE_WINDING_NUMBER_METHOD:
{
typename DerivedV::Scalar dist = (p-center).norm();
Scalar dist = (p-center).norm();
// Radius is already an overestimate of inside
if(dist>1.0*radius)
{
@@ -358,24 +337,22 @@ igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number(const Point & p)
return 0;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number_all(const Point & p) const
template <typename Scalar, typename Index>
inline Scalar
igl::WindingNumberTree<Scalar,Index>::winding_number_all(const Point & p) const
{
return igl::winding_number(V,F,p);
return igl::winding_number(*Vptr,F,p);
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number_boundary(const Point & p) const
template <typename Scalar, typename Index>
inline Scalar
igl::WindingNumberTree<Scalar,Index>::winding_number_boundary(const Point & p) const
{
using namespace Eigen;
using namespace std;
return igl::winding_number(V,cap,p);
return igl::winding_number(*Vptr,cap,p);
}
//template <typename Point, typename DerivedV, typename DerivedF>
//inline double igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number_approx_simple(
//template <typename Scalar, typename Index>
//inline double igl::WindingNumberTree<Scalar,Index>::winding_number_approx_simple(
// const Point & p,
// const double min_max_w)
//{
@@ -390,15 +367,15 @@ igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number_boundary(const P
// }
//}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::print(const char * tab)
template <typename Scalar, typename Index>
inline void igl::WindingNumberTree<Scalar,Index>::print(const char * tab)
{
using namespace std;
// Print all facets
cout<<tab<<"["<<endl<<F<<endl<<"]";
// Print children
for(
typename list<WindingNumberTree<Point,DerivedV,DerivedF>* >::iterator cit = children.begin();
typename list<WindingNumberTree<Scalar,Index>* >::iterator cit = children.begin();
cit != children.end();
cit++)
{
@@ -407,26 +384,26 @@ inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::print(const char *
}
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberTree<Point,DerivedV,DerivedF>::max_abs_winding_number(const Point & /*p*/) const
template <typename Scalar, typename Index>
inline Scalar
igl::WindingNumberTree<Scalar,Index>::max_abs_winding_number(const Point & /*p*/) const
{
return std::numeric_limits<typename DerivedV::Scalar>::infinity();
return std::numeric_limits<Scalar>::infinity();
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberTree<Point,DerivedV,DerivedF>::max_simple_abs_winding_number(
template <typename Scalar, typename Index>
inline Scalar
igl::WindingNumberTree<Scalar,Index>::max_simple_abs_winding_number(
const Point & /*p*/) const
{
using namespace std;
return numeric_limits<typename DerivedV::Scalar>::infinity();
return numeric_limits<Scalar>::infinity();
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberTree<Point,DerivedV,DerivedF>::cached_winding_number(
const igl::WindingNumberTree<Point,DerivedV,DerivedF> & that,
template <typename Scalar, typename Index>
inline Scalar
igl::WindingNumberTree<Scalar,Index>::cached_winding_number(
const igl::WindingNumberTree<Scalar,Index> & that,
const Point & p) const
{
using namespace std;
@@ -450,7 +427,7 @@ igl::WindingNumberTree<Point,DerivedV,DerivedF>::cached_winding_number(
bool is_far = this->radius<that.radius;
if(is_far)
{
typename DerivedV::Scalar a = atan2(
Scalar a = atan2(
that.radius - this->radius,
(that.center - this->center).norm());
assert(a>0);
@@ -475,7 +452,7 @@ igl::WindingNumberTree<Point,DerivedV,DerivedF>::cached_winding_number(
}else
{
for(
typename list<WindingNumberTree<Point,DerivedV,DerivedF>* >::const_iterator cit = children.begin();
typename list<WindingNumberTree<Scalar,Index>* >::const_iterator cit = children.begin();
cit != children.end();
cit++)
{
@@ -493,11 +470,4 @@ igl::WindingNumberTree<Point,DerivedV,DerivedF>::cached_winding_number(
return 0;
}
// Explicit instantiation of static variable
template <
typename Point,
typename DerivedV,
typename DerivedF >
DerivedV igl::WindingNumberTree<Point,DerivedV,DerivedF>::dummyV;
#endif

View File

@@ -0,0 +1,52 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "accumarray.h"
#include <cassert>
template <
typename DerivedS,
typename DerivedV,
typename DerivedA
>
void igl::accumarray(
const Eigen::MatrixBase<DerivedS> & S,
const Eigen::MatrixBase<DerivedV> & V,
Eigen::PlainObjectBase<DerivedA> & A)
{
assert(V.size() == S.size() && "S and V should be same size");
if(S.size() == 0) { A.resize(0,1); return; }
A.setZero(S.maxCoeff()+1,1);
for(int s = 0;s<S.size();s++)
{
A(S(s)) += V(s);
}
}
template <
typename DerivedS,
typename DerivedA
>
void igl::accumarray(
const Eigen::MatrixBase<DerivedS> & S,
const typename DerivedA::Scalar V,
Eigen::PlainObjectBase<DerivedA> & A)
{
if(S.size() == 0) { A.resize(0,1); return; }
A.setZero(S.maxCoeff()+1,1);
for(int s = 0;s<S.size();s++)
{
A(S(s)) += V;
}
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::accumarray<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
template void igl::accumarray<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
#endif

View File

@@ -0,0 +1,47 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef ACCUMARRY_H
#define ACCUMARRY_H
#include "igl_inline.h"
#include <Eigen/Core>
namespace igl
{
/// Accumulate values in V using subscripts in S. Like Matlab's accumarray.
///
/// @param[in] S #S list of subscripts
/// @param[in] V #V list of values
/// @param[out] A max(subs)+1 list of accumulated values
template <
typename DerivedS,
typename DerivedV,
typename DerivedA
>
void accumarray(
const Eigen::MatrixBase<DerivedS> & S,
const Eigen::MatrixBase<DerivedV> & V,
Eigen::PlainObjectBase<DerivedA> & A);
/// Accumulate constant value `V` using subscripts in S. Like Matlab's accumarray.
///
/// @param[in] S #S list of subscripts
/// @param[in] V single value used for all
/// @param[out] A max(subs)+1 list of accumulated values
template <
typename DerivedS,
typename DerivedA
>
void accumarray(
const Eigen::MatrixBase<DerivedS> & S,
const typename DerivedA::Scalar V,
Eigen::PlainObjectBase<DerivedA> & A);
}
#ifndef IGL_STATIC_LIBRARY
# include "accumarray.cpp"
#endif
#endif

View File

@@ -11,6 +11,8 @@
#include "slice_into.h"
#include "cat.h"
//#include "matlab_format.h"
#include "placeholders.h"
#include "PlainMatrix.h"
#include <iostream>
#include <limits>
@@ -31,19 +33,20 @@ template <
>
IGL_INLINE igl::SolverStatus igl::active_set(
const Eigen::SparseMatrix<AT>& A,
const Eigen::PlainObjectBase<DerivedB> & B,
const Eigen::PlainObjectBase<Derivedknown> & known,
const Eigen::PlainObjectBase<DerivedY> & Y,
const Eigen::MatrixBase<DerivedB> & B,
const Eigen::MatrixBase<Derivedknown> & known,
const Eigen::MatrixBase<DerivedY> & Y,
const Eigen::SparseMatrix<AeqT>& Aeq,
const Eigen::PlainObjectBase<DerivedBeq> & Beq,
const Eigen::MatrixBase<DerivedBeq> & Beq,
const Eigen::SparseMatrix<AieqT>& Aieq,
const Eigen::PlainObjectBase<DerivedBieq> & Bieq,
const Eigen::PlainObjectBase<Derivedlx> & p_lx,
const Eigen::PlainObjectBase<Derivedux> & p_ux,
const Eigen::MatrixBase<DerivedBieq> & Bieq,
const Eigen::MatrixBase<Derivedlx> & p_lx,
const Eigen::MatrixBase<Derivedux> & p_ux,
const igl::active_set_params & params,
Eigen::PlainObjectBase<DerivedZ> & Z
)
{
//#define ACTIVE_SET_CPP_DEBUG
#if defined(ACTIVE_SET_CPP_DEBUG) && !defined(_MSC_VER)
# warning "ACTIVE_SET_CPP_DEBUG"
@@ -109,9 +112,7 @@ IGL_INLINE igl::SolverStatus igl::active_set(
Matrix<BOOL,Dynamic,1> as_ieq = Matrix<BOOL,Dynamic,1>::Constant(Aieq.rows(),1,FALSE);
// Keep track of previous Z for comparison
DerivedZ old_Z;
old_Z = DerivedZ::Constant(
n,1,numeric_limits<typename DerivedZ::Scalar>::max());
PlainMatrix<DerivedZ> old_Z;
int iter = 0;
while(true)
@@ -121,35 +122,43 @@ IGL_INLINE igl::SolverStatus igl::active_set(
cout<<" pre"<<endl;
#endif
// FIND BREACHES OF CONSTRAINTS
#ifdef ACTIVE_SET_CPP_DEBUG
int new_as_lx = 0;
int new_as_ux = 0;
int new_as_ieq = 0;
#endif
if(Z.size() > 0)
{
for(int z = 0;z < n;z++)
{
if(Z(z) < lx(z))
{
#ifdef ACTIVE_SET_CPP_DEBUG
new_as_lx += (as_lx(z)?0:1);
#endif
//new_as_lx++;
as_lx(z) = TRUE;
}
if(Z(z) > ux(z))
{
#ifdef ACTIVE_SET_CPP_DEBUG
new_as_ux += (as_ux(z)?0:1);
#endif
//new_as_ux++;
as_ux(z) = TRUE;
}
}
if(Aieq.rows() > 0)
{
DerivedZ AieqZ;
PlainMatrix<DerivedZ,Eigen::Dynamic> AieqZ;
AieqZ = Aieq*Z;
for(int a = 0;a<Aieq.rows();a++)
{
if(AieqZ(a) > Bieq(a))
{
#ifdef ACTIVE_SET_CPP_DEBUG
new_as_ieq += (as_ieq(a)?0:1);
#endif
as_ieq(a) = TRUE;
}
}
@@ -158,14 +167,17 @@ IGL_INLINE igl::SolverStatus igl::active_set(
cout<<" new_as_lx: "<<new_as_lx<<endl;
cout<<" new_as_ux: "<<new_as_ux<<endl;
#endif
const double diff = (Z-old_Z).squaredNorm();
#ifdef ACTIVE_SET_CPP_DEBUG
cout<<"diff: "<<diff<<endl;
#endif
if(diff < params.solution_diff_threshold)
if(iter > 0)
{
ret = SOLVER_STATUS_CONVERGED;
break;
const double diff = (Z-old_Z).squaredNorm();
#ifdef ACTIVE_SET_CPP_DEBUG
cout<<"diff: "<<diff<<endl;
#endif
if(diff < params.solution_diff_threshold)
{
ret = SOLVER_STATUS_CONVERGED;
break;
}
}
old_Z = Z;
}
@@ -190,9 +202,9 @@ IGL_INLINE igl::SolverStatus igl::active_set(
#endif
// PREPARE FIXED VALUES
Derivedknown known_i;
Eigen::Matrix<typename Derivedknown::Scalar,Eigen::Dynamic,1> known_i;
known_i.resize(nk + as_lx_count + as_ux_count,1);
DerivedY Y_i;
PlainMatrix<DerivedY,Eigen::Dynamic,1> Y_i;
Y_i.resize(nk + as_lx_count + as_ux_count,1);
{
known_i.block(0,0,known.rows(),known.cols()) = known;
@@ -223,9 +235,9 @@ IGL_INLINE igl::SolverStatus igl::active_set(
}
//cout<<matlab_format((known_i.array()+1).eval(),"known_i")<<endl;
// PREPARE EQUALITY CONSTRAINTS
VectorXi as_ieq_list(as_ieq_count,1);
Eigen::Matrix<typename DerivedY::Scalar, Eigen::Dynamic, 1> as_ieq_list(as_ieq_count,1);
// Gather active constraints and resp. rhss
DerivedBeq Beq_i;
PlainMatrix<DerivedBeq,Eigen::Dynamic,1> Beq_i;
Beq_i.resize(Beq.rows()+as_ieq_count,1);
Beq_i.head(Beq.rows()) = Beq;
{
@@ -262,7 +274,7 @@ IGL_INLINE igl::SolverStatus igl::active_set(
}
#endif
DerivedZ sol;
PlainMatrix<DerivedZ,Eigen::Dynamic,Eigen::Dynamic> sol;
if(known_i.size() == A.rows())
{
// Everything's fixed?
@@ -270,7 +282,7 @@ IGL_INLINE igl::SolverStatus igl::active_set(
cout<<" everything's fixed."<<endl;
#endif
Z.resize(A.rows(),Y_i.cols());
slice_into(Y_i,known_i,1,Z);
Z(known_i,igl::placeholders::all) = Y_i;
sol.resize(0,Y_i.cols());
assert(Aeq_i.rows() == 0 && "All fixed but linearly constrained");
}else
@@ -280,11 +292,15 @@ IGL_INLINE igl::SolverStatus igl::active_set(
#endif
if(!min_quad_with_fixed_precompute(A,known_i,Aeq_i,params.Auu_pd,data))
{
#ifdef ACTIVE_SET_CPP_DEBUG
cerr<<"Error: min_quad_with_fixed precomputation failed."<<endl;
#endif
if(iter > 0 && Aeq_i.rows() > Aeq.rows())
{
#ifdef ACTIVE_SET_CPP_DEBUG
cerr<<" *Are you sure rows of [Aeq;Aieq] are linearly independent?*"<<
endl;
#endif
}
ret = SOLVER_STATUS_ERROR;
break;
@@ -294,7 +310,9 @@ IGL_INLINE igl::SolverStatus igl::active_set(
#endif
if(!min_quad_with_fixed_solve(data,B,Y_i,Beq_i,Z,sol))
{
#ifdef ACTIVE_SET_CPP_DEBUG
cerr<<"Error: min_quad_with_fixed solve failed."<<endl;
#endif
ret = SOLVER_STATUS_ERROR;
break;
}
@@ -311,8 +329,8 @@ IGL_INLINE igl::SolverStatus igl::active_set(
SparseMatrix<AT> Ak;
// Slow
slice(A,known_i,1,Ak);
DerivedB Bk;
slice(B,known_i,Bk);
//slice(B,known_i,Bk);
PlainMatrix<DerivedB,Eigen::Dynamic> Bk = B(known_i,igl::placeholders::all);
MatrixXd Lambda_known_i = -(0.5*Ak*Z + 0.5*Bk);
// reverse the lambda values for lx
Lambda_known_i.block(nk,0,as_lx_count,1) =
@@ -345,7 +363,7 @@ IGL_INLINE igl::SolverStatus igl::active_set(
{
if(Lambda_Aieq_i(a) < params.inactive_threshold)
{
as_ieq(as_ieq_list(a)) = FALSE;
as_ieq(int(as_ieq_list(a))) = FALSE;
}
}
@@ -365,6 +383,6 @@ IGL_INLINE igl::SolverStatus igl::active_set(
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template igl::SolverStatus igl::active_set<double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, igl::active_set_params const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
template igl::SolverStatus igl::active_set<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, igl::active_set_params const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template igl::SolverStatus igl::active_set<double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::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::SparseMatrix<double, 0, int> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, igl::active_set_params const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
template igl::SolverStatus igl::active_set<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::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::SparseMatrix<double, 0, int> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, igl::active_set_params const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
#endif

View File

@@ -16,39 +16,45 @@
namespace igl
{
struct active_set_params;
// Known Bugs: rows of [Aeq;Aieq] **must** be linearly independent. Should be
// using QR decomposition otherwise:
// http://www.okstate.edu/sas/v8/sashtml/ormp/chap5/sect32.htm
//
// ACTIVE_SET Minimize quadratic energy
//
// 0.5*Z'*A*Z + Z'*B + C with constraints
//
// that Z(known) = Y, optionally also subject to the constraints Aeq*Z = Beq,
// and further optionally subject to the linear inequality constraints that
// Aieq*Z <= Bieq and constant inequality constraints lx <= x <= ux
//
// Inputs:
// A n by n matrix of quadratic coefficients
// B n by 1 column of linear coefficients
// known list of indices to known rows in Z
// Y list of fixed values corresponding to known rows in Z
// Aeq meq by n list of linear equality constraint coefficients
// Beq meq by 1 list of linear equality constraint constant values
// Aieq mieq by n list of linear inequality constraint coefficients
// Bieq mieq by 1 list of linear inequality constraint constant values
// lx n by 1 list of lower bounds [] implies -Inf
// ux n by 1 list of upper bounds [] implies Inf
// params struct of additional parameters (see below)
// Z if not empty, is taken to be an n by 1 list of initial guess values
// (see output)
// Outputs:
// Z n by 1 list of solution values
// Returns true on success, false on error
//
// Benchmark: For a harmonic solve on a mesh with 325K facets, matlab 2.2
// secs, igl/min_quad_with_fixed.h 7.1 secs
//
///
/// Minimize convex quadratic energy subject to linear inequality constraints
///
/// min ½ Zᵀ A Z + Zᵀ B + constant
/// Z
/// subject to
/// Aeq Z = Beq
/// Aieq Z <= Bieq
/// lx <= Z <= ux
/// Z(known) = Y
///
/// that Z(known) = Y, optionally also subject to the constraints Aeq*Z = Beq,
/// and further optionally subject to the linear inequality constraints that
/// Aieq*Z <= Bieq and constant inequality constraints lx <= x <= ux
///
/// @param[in] A n by n matrix of quadratic coefficients
/// @param[in] B n by 1 column of linear coefficients
/// @param[in] known list of indices to known rows in Z
/// @param[in] Y list of fixed values corresponding to known rows in Z
/// @param[in] Aeq meq by n list of linear equality constraint coefficients
/// @param[in] Beq meq by 1 list of linear equality constraint constant values
/// @param[in] Aieq mieq by n list of linear inequality constraint coefficients
/// @param[in] Bieq mieq by 1 list of linear inequality constraint constant values
/// @param[in] lx n by 1 list of lower bounds [] implies -Inf
/// @param[in] ux n by 1 list of upper bounds [] implies Inf
/// @param[in] params struct of additional parameters (see below)
/// @param[in,out] Z if not empty, is taken to be an n by 1 list of initial guess values. Set to solution on output.
/// @return true on success, false on error
///
/// \note Benchmark: For a harmonic solve on a mesh with 325K facets, matlab 2.2
/// secs, igl/min_quad_with_fixed.h 7.1 secs
///
/// \pre rows of [Aeq;Aieq] **must** be linearly independent. Should be
/// using QR decomposition otherwise:
/// https://v8doc.sas.com/sashtml/ormp/chap5/sect32.htm
///
/// \warning This solver is fairly experimental. It works reasonably well for
/// bbw problems but doesn't generalize well to other problems. NASOQ and
/// OSQP are better general purpose solvers.
template <
typename AT,
typename DerivedB,
@@ -64,37 +70,40 @@ namespace igl
>
IGL_INLINE igl::SolverStatus active_set(
const Eigen::SparseMatrix<AT>& A,
const Eigen::PlainObjectBase<DerivedB> & B,
const Eigen::PlainObjectBase<Derivedknown> & known,
const Eigen::PlainObjectBase<DerivedY> & Y,
const Eigen::MatrixBase<DerivedB> & B,
const Eigen::MatrixBase<Derivedknown> & known,
const Eigen::MatrixBase<DerivedY> & Y,
const Eigen::SparseMatrix<AeqT>& Aeq,
const Eigen::PlainObjectBase<DerivedBeq> & Beq,
const Eigen::MatrixBase<DerivedBeq> & Beq,
const Eigen::SparseMatrix<AieqT>& Aieq,
const Eigen::PlainObjectBase<DerivedBieq> & Bieq,
const Eigen::PlainObjectBase<Derivedlx> & lx,
const Eigen::PlainObjectBase<Derivedux> & ux,
const Eigen::MatrixBase<DerivedBieq> & Bieq,
const Eigen::MatrixBase<Derivedlx> & lx,
const Eigen::MatrixBase<Derivedux> & ux,
const igl::active_set_params & params,
Eigen::PlainObjectBase<DerivedZ> & Z
);
};
#include "EPS.h"
/// Input parameters controling active_set
///
/// \fileinfo
struct igl::active_set_params
{
// Input parameters for active_set:
// Auu_pd whether Auu is positive definite {false}
// max_iter Maximum number of iterations (0 = Infinity, {100})
// inactive_threshold Threshold on Lagrange multiplier values to determine
// whether to keep constraints active {EPS}
// constraint_threshold Threshold on whether constraints are violated (0
// is perfect) {EPS}
// solution_diff_threshold Threshold on the squared norm of the difference
// between two consecutive solutions {EPS}
/// Auu_pd whether Auu is positive definite {false}
bool Auu_pd;
/// max_iter Maximum number of iterations (0 = Infinity, {100})
int max_iter;
/// inactive_threshold Threshold on Lagrange multiplier values to determine
/// whether to keep constraints active {EPS}
double inactive_threshold;
/// constraint_threshold Threshold on whether constraints are violated (0
/// is perfect) {EPS}
double constraint_threshold;
/// solution_diff_threshold Threshold on the squared norm of the difference
/// between two consecutive solutions {EPS}
double solution_diff_threshold;
/// @private
active_set_params():
Auu_pd(false),
max_iter(100),

View File

@@ -12,7 +12,7 @@
template <typename Index, typename IndexVector>
IGL_INLINE void igl::adjacency_list(
const Eigen::PlainObjectBase<Index> & F,
const Eigen::MatrixBase<Index> & F,
std::vector<std::vector<IndexVector> >& A,
bool sorted)
{
@@ -70,6 +70,7 @@ IGL_INLINE void igl::adjacency_list(
for(int v=0; v<(int)SR.size();++v)
{
std::vector<IndexVector>& vv = A.at(v);
if(vv.size() == 0){ continue; }
std::vector<std::vector<int> >& sr = SR[v];
std::vector<std::vector<int> > pn = sr;
@@ -132,8 +133,18 @@ IGL_INLINE void igl::adjacency_list(
const std::vector<std::vector<Index> > & F,
std::vector<std::vector<Index> >& A)
{
A.clear();
A.resize(F.maxCoeff()+1);
A.clear();
// Find maxCoeff
Index maxCoeff = 0;
for(const auto &vec : F)
{
for(int coeff : vec)
{
maxCoeff = std::max(coeff, maxCoeff);
}
}
A.resize(maxCoeff + 1);
// Loop over faces
for(int i = 0;i<F.size();i++)
@@ -142,8 +153,8 @@ IGL_INLINE void igl::adjacency_list(
for(int j = 0;j<F[i].size();j++)
{
// Get indices of edge: s --> d
int s = F(i,j);
int d = F(i,(j+1)%F[i].size());
int s = F[i][j];
int d = F[i][(j+1)%F[i].size()];
A.at(s).push_back(d);
A.at(d).push_back(s);
}
@@ -161,8 +172,10 @@ IGL_INLINE void igl::adjacency_list(
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::adjacency_list<Eigen::Matrix<int, -1, 2, 0, -1, 2>, int>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, bool);
template void igl::adjacency_list<Eigen::Matrix<int, -1, 2, 0, -1, 2>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, bool);
// generated by autoexplicit.sh
template void igl::adjacency_list<Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::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> > > >&, bool);
template void igl::adjacency_list<Eigen::Matrix<int, -1, 3, 0, -1, 3>, int>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, bool);
template void igl::adjacency_list<Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, bool);
template void igl::adjacency_list<Eigen::Matrix<int, -1, 3, 0, -1, 3>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, bool);
template void igl::adjacency_list<class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned int>(class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1> > const &, class std::vector<class std::vector<unsigned int, class std::allocator<unsigned int> >, class std::allocator<class std::vector<unsigned int, class std::allocator<unsigned int> > > > &, bool);
template void igl::adjacency_list<int>(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
#endif

View File

@@ -14,29 +14,35 @@
#include <vector>
namespace igl
{
// Constructs the graph adjacency list of a given mesh (V,F)
// Templates:
// T should be a eigen sparse matrix primitive type like int or double
// Inputs:
// F #F by dim list of mesh faces (must be triangles)
// sorted flag that indicates if the list should be sorted counter-clockwise
// Outputs:
// A vector<vector<T> > containing at row i the adjacent vertices of vertex i
//
// Example:
// // Mesh in (V,F)
// vector<vector<double> > A;
// adjacency_list(F,A);
//
// See also: edges, cotmatrix, diag
/// Constructs the graph adjacency list of a given mesh (V,F)
///
/// @tparam T should be a eigen sparse matrix primitive type like int or double
/// @param[in] F #F by dim list of mesh faces (must be triangles)
/// @param[out] A vector<vector<T> > containing at row i the adjacent vertices of vertex i
/// @param[in] sorted flag that indicates if the list should be sorted counter-clockwise. Input assumed to be manifold.
///
/// Example:
/// \code{.cpp}
/// // Mesh in (V,F)
/// vector<vector<double> > A;
/// adjacency_list(F,A);
/// \endcode
///
/// \see
/// adjacency_matrix
/// edges,
/// cotmatrix,
/// diag
template <typename Index, typename IndexVector>
IGL_INLINE void adjacency_list(
const Eigen::PlainObjectBase<Index> & F,
const Eigen::MatrixBase<Index> & F,
std::vector<std::vector<IndexVector> >& A,
bool sorted = false);
// Variant that accepts polygonal faces.
// Each element of F is a set of indices of a polygonal face.
/// Constructs the graph adjacency list of a given _polygon_ mesh (V,F)
///
/// @tparam T should be a eigen sparse matrix primitive type like int or double
/// @param[in] F #F list of polygon face index lists
/// @param[out] A vector<vector<T> > containing at row i the adjacent vertices of vertex i
template <typename Index>
IGL_INLINE void adjacency_list(
const std::vector<std::vector<Index> > & F,

View File

@@ -1,9 +1,9 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "adjacency_matrix.h"
@@ -13,7 +13,7 @@
template <typename DerivedF, typename T>
IGL_INLINE void igl::adjacency_matrix(
const Eigen::MatrixBase<DerivedF> & F,
const Eigen::MatrixBase<DerivedF> & F,
Eigen::SparseMatrix<T>& A)
{
using namespace std;
@@ -65,10 +65,61 @@ IGL_INLINE void igl::adjacency_matrix(
}
}
template <typename DerivedI, typename DerivedC, typename T>
IGL_INLINE void igl::adjacency_matrix(
const Eigen::MatrixBase<DerivedI> & I,
const Eigen::MatrixBase<DerivedC> & C,
Eigen::SparseMatrix<T>& A)
{
using namespace std;
using namespace Eigen;
typedef Triplet<T> IJV;
vector<IJV > ijv;
ijv.reserve(C(C.size()-1)*2);
typedef typename DerivedI::Scalar Index;
const Index n = I.maxCoeff()+1;
{
// loop over polygons
for(Index p = 0;p<C.size()-1;p++)
{
// number of edges
const Index np = C(p+1)-C(p);
// loop over edges
for(Index c = 0;c<np;c++)
{
const Index i = I(C(p)+c);
const Index j = I(C(p)+((c+1)%np));
ijv.emplace_back(i,j,1);
ijv.emplace_back(j,i,1);
}
}
}
A.resize(n,n);
A.reserve(6*n);
A.setFromTriplets(ijv.begin(),ijv.end());
// Force all non-zeros to be one
// Iterate over outside
for(int k=0; k<A.outerSize(); ++k)
{
// Iterate over inside
for(typename Eigen::SparseMatrix<T>::InnerIterator it (A,k); it; ++it)
{
assert(it.value() != 0);
A.coeffRef(it.row(),it.col()) = 1;
}
}
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<int, 0, int>& );
// generated by autoexplicit.sh
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, -1, 0, -1, -1>, bool>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<bool, 0, int>&);
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<int, 0, int>&);
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, 3, 0, -1, 3>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::SparseMatrix<int, 0, int>&);
#endif

View File

@@ -15,33 +15,49 @@
namespace igl
{
// Constructs the graph adjacency matrix of a given mesh (V,F)
// Templates:
// T should be a eigen sparse matrix primitive type like int or double
// Inputs:
// F #F by dim list of mesh simplices
// Outputs:
// A max(F) by max(F) cotangent matrix, each row i corresponding to V(i,:)
//
// Example:
// // Mesh in (V,F)
// Eigen::SparseMatrix<double> A;
// adjacency_matrix(F,A);
// // sum each row
// SparseVector<double> Asum;
// sum(A,1,Asum);
// // Convert row sums into diagonal of sparse matrix
// SparseMatrix<double> Adiag;
// diag(Asum,Adiag);
// // Build uniform laplacian
// SparseMatrix<double> U;
// U = A-Adiag;
//
// See also: edges, cotmatrix, diag
/// Constructs the graph adjacency matrix of a given mesh (V,F)
///
/// @tparam T should be a eigen sparse matrix primitive type like `int` or `double`
/// @param[in] F #F by dim list of mesh simplices
/// @param[out] A max(F)+1 by max(F)+1 adjacency matrix, each row i corresponding to V(i,:)
///
/// #### Example
/// \code{.cpp}
/// // Mesh in (V,F)
/// Eigen::SparseMatrix<double> A;
/// adjacency_matrix(F,A);
/// // sum each row
/// SparseVector<double> Asum;
/// sum(A,1,Asum);
/// // Convert row sums into diagonal of sparse matrix
/// SparseMatrix<double> Adiag;
/// diag(Asum,Adiag);
/// // Build uniform laplacian
/// SparseMatrix<double> U;
/// U = A-Adiag;
/// \endcode
///
/// \see
/// edges,
/// cotmatrix,
/// diag
template <typename DerivedF, typename T>
IGL_INLINE void adjacency_matrix(
const Eigen::MatrixBase<DerivedF> & F,
Eigen::SparseMatrix<T>& A);
/// Constructs an vertex adjacency for a polygon mesh.
///
/// @param[in] I #I vectorized list of polygon corner indices into rows of some matrix V
/// @param[in] C #polygons+1 list of cumulative polygon sizes so that C(i+1)-C(i) =
/// size of the ith polygon, and so I(C(i)) through I(C(i+1)-1) are the
/// indices of the ith polygon
/// @param[out] A max(I)+1 by max(I)+1 adjacency matrix, each row i corresponding to V(i,:)
///
template <typename DerivedI, typename DerivedC, typename T>
IGL_INLINE void adjacency_matrix(
const Eigen::MatrixBase<DerivedI> & I,
const Eigen::MatrixBase<DerivedC> & C,
Eigen::SparseMatrix<T>& A);
}
#ifndef IGL_STATIC_LIBRARY

View File

@@ -12,16 +12,15 @@
#include <Eigen/Sparse>
namespace igl
{
// For Dense matrices use: A.rowwise().all() or A.colwise().all()
//
// Inputs:
// A m by n sparse matrix
// dim dimension along which to check for all (1 or 2)
// Output:
// B n-long vector (if dim == 1)
// or
// B m-long vector (if dim == 2)
//
/// Check whether all values are logically true along a dimension.
///
/// \note For Dense matrices use: A.rowwise().all() or A.colwise().all()
///
/// @param[in] A m by n sparse matrix
/// @param[in] dim dimension along which to check for all (1 or 2)
/// @param[out] B n-long vector (if dim == 1)
/// or m-long vector (if dim == 2)
///
template <typename AType, typename DerivedB>
IGL_INLINE void all(
const Eigen::SparseMatrix<AType> & A,

View File

@@ -1,26 +0,0 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "all_edges.h"
#include "oriented_facets.h"
template <typename DerivedF, typename DerivedE>
IGL_INLINE void igl::all_edges(
const Eigen::MatrixBase<DerivedF> & F,
Eigen::PlainObjectBase<DerivedE> & E)
{
return oriented_facets(F,E);
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template void igl::all_edges<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
template void igl::all_edges<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
template void igl::all_edges<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
template void igl::all_edges<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
template void igl::all_edges<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
#endif

View File

@@ -1,38 +0,0 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ALL_EDGES_H
#define IGL_ALL_EDGES_H
#include "igl_inline.h"
#include <Eigen/Dense>
namespace igl
{
// Deprecated: call oriented_facets instead.
//
// ALL_EDGES Determines all "directed edges" of a given set of simplices. For
// a manifold mesh, this computes all of the half-edges
//
// Inputs:
// F #F by simplex_size list of "faces"
// Outputs:
// E #E by simplex_size-1 list of edges
//
// Note: this is not the same as igl::edges because this includes every
// directed edge including repeats (meaning interior edges on a surface will
// show up once for each direction and non-manifold edges may appear more than
// once for each direction).
template <typename DerivedF, typename DerivedE>
IGL_INLINE void all_edges(
const Eigen::MatrixBase<DerivedF> & F,
Eigen::PlainObjectBase<DerivedE> & E);
}
#ifndef IGL_STATIC_LIBRARY
# include "all_edges.cpp"
#endif
#endif

View File

@@ -11,21 +11,16 @@
namespace igl
{
// ALL_PAIRS_DISTANCES compute distances between each point i in V and point j
// in U
//
// D = all_pairs_distances(V,U)
//
// Templates:
// Mat matrix class like MatrixXd
// Inputs:
// V #V by dim list of points
// U #U by dim list of points
// squared whether to return squared distances
// Outputs:
// D #V by #U matrix of distances, where D(i,j) gives the distance or
// squareed distance between V(i,:) and U(j,:)
//
/// Compute distances between each point i in V and point j in U
///
/// D = all_pairs_distances(V,U)
///
/// @tparam matrix class like MatrixXd
/// @param[in] V #V by dim list of points
/// @param[in] U #U by dim list of points
/// @param[in] squared whether to return squared distances
/// @param[out] D #V by #U matrix of distances, where D(i,j) gives the distance or
/// squareed distance between V(i,:) and U(j,:)
template <typename Mat>
IGL_INLINE void all_pairs_distances(
const Mat & V,

View File

@@ -22,11 +22,11 @@ template <
IGL_INLINE void igl::ambient_occlusion(
const std::function<
bool(
const Eigen::Vector3f&,
const Eigen::Vector3f&)
const Eigen::Matrix<typename DerivedP::Scalar,3,1> &,
const Eigen::Matrix<typename DerivedP::Scalar,3,1> &)
> & shoot_ray,
const Eigen::PlainObjectBase<DerivedP> & P,
const Eigen::PlainObjectBase<DerivedN> & N,
const Eigen::MatrixBase<DerivedP> & P,
const Eigen::MatrixBase<DerivedN> & N,
const int num_samples,
Eigen::PlainObjectBase<DerivedS> & S)
{
@@ -35,16 +35,19 @@ IGL_INLINE void igl::ambient_occlusion(
// Resize output
S.resize(n,1);
// Embree seems to be parallel when constructing but not when tracing rays
const MatrixXf D = random_dir_stratified(num_samples).cast<float>();
typedef typename DerivedP::Scalar Scalar;
typedef Eigen::Matrix<Scalar,3,1> Vector3N;
const Matrix<Scalar,Eigen::Dynamic,3> D = random_dir_stratified(num_samples).cast<Scalar>();
const auto & inner = [&P,&N,&num_samples,&D,&S,&shoot_ray](const int p)
{
const Vector3f origin = P.row(p).template cast<float>();
const Vector3f normal = N.row(p).template cast<float>();
const Vector3N origin = P.row(p);
const Vector3N normal = N.row(p);
int num_hits = 0;
for(int s = 0;s<num_samples;s++)
{
Vector3f d = D.row(s);
Vector3N d = D.row(s);
if(d.dot(normal) < 0)
{
// reverse ray
@@ -69,24 +72,26 @@ template <
typename DerivedS >
IGL_INLINE void igl::ambient_occlusion(
const igl::AABB<DerivedV,DIM> & aabb,
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedF> & F,
const Eigen::PlainObjectBase<DerivedP> & P,
const Eigen::PlainObjectBase<DerivedN> & N,
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F,
const Eigen::MatrixBase<DerivedP> & P,
const Eigen::MatrixBase<DerivedN> & N,
const int num_samples,
Eigen::PlainObjectBase<DerivedS> & S)
{
typedef typename DerivedV::Scalar Scalar;
using Vector3S = Eigen::Matrix<Scalar,3,1>;
const auto & shoot_ray = [&aabb,&V,&F](
const Eigen::Vector3f& _s,
const Eigen::Vector3f& dir)->bool
const Eigen::Matrix<Scalar,3,1> & _s,
const Eigen::Matrix<Scalar,3,1> & dir)->bool
{
Eigen::Vector3f s = _s+1e-4*dir;
igl::Hit hit;
Vector3S s = _s+1e-4*dir;
igl::Hit<Scalar> hit;
return aabb.intersect_ray(
V,
F,
s .cast<typename DerivedV::Scalar>().eval(),
dir.cast<typename DerivedV::Scalar>().eval(),
s,
dir,
hit);
};
return ambient_occlusion(shoot_ray,P,N,num_samples,S);
@@ -100,22 +105,24 @@ template <
typename DerivedN,
typename DerivedS >
IGL_INLINE void igl::ambient_occlusion(
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedF> & F,
const Eigen::PlainObjectBase<DerivedP> & P,
const Eigen::PlainObjectBase<DerivedN> & N,
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F,
const Eigen::MatrixBase<DerivedP> & P,
const Eigen::MatrixBase<DerivedN> & N,
const int num_samples,
Eigen::PlainObjectBase<DerivedS> & S)
{
typedef typename DerivedV::Scalar Scalar;
using Vector3S = Eigen::Matrix<Scalar,3,1>;
if(F.rows() < 100)
{
// Super naive
const auto & shoot_ray = [&V,&F](
const Eigen::Vector3f& _s,
const Eigen::Vector3f& dir)->bool
const Eigen::Matrix<Scalar,3,1> & _s,
const Eigen::Matrix<Scalar,3,1> & dir)->bool
{
Eigen::Vector3f s = _s+1e-4*dir;
igl::Hit hit;
Vector3S s = _s+1e-4*dir;
igl::Hit<Scalar> hit;
return ray_mesh_intersect(s,dir,V,F,hit);
};
return ambient_occlusion(shoot_ray,P,N,num_samples,S);
@@ -127,11 +134,12 @@ IGL_INLINE void igl::ambient_occlusion(
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
// generated by autoexplicit.sh
template void igl::ambient_occlusion<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
// generated by autoexplicit.sh
template void igl::ambient_occlusion<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
template void igl::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template void igl::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
template void igl::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<double, 3, 1, 0, 3, 1> const&, Eigen::Matrix<double, 3, 1, 0, 3, 1> const&)> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
template void igl::ambient_occlusion<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<double, 3, 1, 0, 3, 1> const&, Eigen::Matrix<double, 3, 1, 0, 3, 1> const&)> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
template void igl::ambient_occlusion<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<double, 3, 1, 0, 3, 1> const&, Eigen::Matrix<double, 3, 1, 0, 3, 1> const&)> const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
template void igl::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::function<bool (Eigen::Matrix<double, 3, 1, 0, 3, 1> const&, Eigen::Matrix<double, 3, 1, 0, 3, 1> const&)> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template void igl::ambient_occlusion<Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, -1, 1, 0, -1, 1>>(std::function<bool (Eigen::Matrix<Eigen::Matrix<float, 1, 3, 1, 1, 3>::Scalar, 3, 1, 0, 3, 1> const&, Eigen::Matrix<Eigen::Matrix<float, 1, 3, 1, 1, 3>::Scalar, 3, 1, 0, 3, 1> const&)> const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3>> const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3>> const&, int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1>>&);
template void igl::ambient_occlusion<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 1, 0, -1, 1>>(std::function<bool (Eigen::Matrix<Eigen::Matrix<float, -1, 3, 0, -1, 3>::Scalar, 3, 1, 0, 3, 1> const&, Eigen::Matrix<Eigen::Matrix<float, -1, 3, 0, -1, 3>::Scalar, 3, 1, 0, 3, 1> const&)> const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3>> const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3>> const&, int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1>>&);
template void igl::ambient_occlusion<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 1, 0, -1, 1>>(std::function<bool (Eigen::Matrix<Eigen::Matrix<float, -1, -1, 0, -1, -1>::Scalar, 3, 1, 0, 3, 1> const&, Eigen::Matrix<Eigen::Matrix<float, -1, -1, 0, -1, -1>::Scalar, 3, 1, 0, 3, 1> const&)> const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1>> const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1>> const&, int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1>>&);
#endif

View File

@@ -13,17 +13,17 @@
#include <functional>
namespace igl
{
// Compute ambient occlusion per given point
//
// Inputs:
// shoot_ray function handle that outputs hits of a given ray against a
// mesh (embedded in function handles as captured variable/data)
// P #P by 3 list of origin points
// N #P by 3 list of origin normals
// Outputs:
// S #P list of ambient occlusion values between 1 (fully occluded) and
// 0 (not occluded)
//
/// Compute ambient occlusion per given point using ray-mesh intersection
/// function handle.
///
/// @param[in] shoot_ray function handle that outputs hits of a given ray against a
/// mesh (embedded in function handles as captured variable/data)
/// @param[in] P #P by 3 list of origin points
/// @param[in] N #P by 3 list of origin normals
/// @param[in] num_samples number of samples to use (e.g., 1000)
/// @param[out] S #P list of ambient occlusion values between 1 (fully occluded) and
/// 0 (not occluded)
///
template <
typename DerivedP,
typename DerivedN,
@@ -31,15 +31,25 @@ namespace igl
IGL_INLINE void ambient_occlusion(
const std::function<
bool(
const Eigen::Vector3f&,
const Eigen::Vector3f&)
const Eigen::Matrix<typename DerivedP::Scalar,3,1>&,
const Eigen::Matrix<typename DerivedP::Scalar,3,1>&)
> & shoot_ray,
const Eigen::PlainObjectBase<DerivedP> & P,
const Eigen::PlainObjectBase<DerivedN> & N,
const Eigen::MatrixBase<DerivedP> & P,
const Eigen::MatrixBase<DerivedN> & N,
const int num_samples,
Eigen::PlainObjectBase<DerivedS> & S);
// Inputs:
// AABB axis-aligned bounding box hierarchy around (V,F)
/// Compute ambient occlusion per given point for mesh (V,F) with precomputed
/// AABB tree.
///
// @param[in] AABB axis-aligned bounding box hierarchy around (V,F)
/// @param[in] V #V by 3 list of mesh vertex positions
/// @param[in] F #F by 3 list of mesh face indices into V
/// @param[in] P #P by 3 list of origin points
/// @param[in] N #P by 3 list of origin normals
/// @param[in] num_samples number of samples to use (e.g., 1000)
/// @param[out] S #P list of ambient occlusion values between 1 (fully occluded) and
/// 0 (not occluded)
///
template <
typename DerivedV,
int DIM,
@@ -49,15 +59,21 @@ namespace igl
typename DerivedS >
IGL_INLINE void ambient_occlusion(
const igl::AABB<DerivedV,DIM> & aabb,
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedF> & F,
const Eigen::PlainObjectBase<DerivedP> & P,
const Eigen::PlainObjectBase<DerivedN> & N,
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F,
const Eigen::MatrixBase<DerivedP> & P,
const Eigen::MatrixBase<DerivedN> & N,
const int num_samples,
Eigen::PlainObjectBase<DerivedS> & S);
// Inputs:
// V #V by 3 list of mesh vertex positions
// F #F by 3 list of mesh face indices into V
/// Compute ambient occlusion per given point for mesh (V,F)
///
/// @param[in] V #V by 3 list of mesh vertex positions
/// @param[in] F #F by 3 list of mesh face indices into V
/// @param[in] P #P by 3 list of origin points
/// @param[in] N #P by 3 list of origin normals
/// @param[in] num_samples number of samples to use (e.g., 1000)
/// @param[out] S #P list of ambient occlusion values between 1 (fully occluded) and
/// 0 (not occluded)
template <
typename DerivedV,
typename DerivedF,
@@ -65,10 +81,10 @@ namespace igl
typename DerivedN,
typename DerivedS >
IGL_INLINE void ambient_occlusion(
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedF> & F,
const Eigen::PlainObjectBase<DerivedP> & P,
const Eigen::PlainObjectBase<DerivedN> & N,
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F,
const Eigen::MatrixBase<DerivedP> & P,
const Eigen::MatrixBase<DerivedN> & N,
const int num_samples,
Eigen::PlainObjectBase<DerivedS> & S);

View File

@@ -6,8 +6,8 @@
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "angular_distance.h"
#include <igl/EPS.h>
#include <igl/PI.h>
#include "EPS.h"
#include "PI.h"
IGL_INLINE double igl::angular_distance(
const Eigen::Quaterniond & A,
const Eigen::Quaterniond & B)

View File

@@ -11,13 +11,12 @@
#include <Eigen/Geometry>
namespace igl
{
// The "angular distance" between two unit quaternions is the angle of the
// smallest rotation (treated as an Axis and Angle) that takes A to B.
//
// Inputs:
// A unit quaternion
// B unit quaternion
// Returns angular distance
/// The "angular distance" between two unit quaternions is the angle of the
/// smallest rotation (treated as an Axis and Angle) that takes A to B.
///
/// @param[in] A unit quaternion
/// @param[in] B unit quaternion
/// @return angular distance
IGL_INLINE double angular_distance(
const Eigen::Quaterniond & A,
const Eigen::Quaterniond & B);

View File

@@ -1,934 +0,0 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "ReAntTweakBar.h"
#include <cstdio>
#include <cstring>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <map>
// GLOBAL WRAPPERS
namespace
{
std::map<
TwType,std::pair<const char *,std::vector<TwEnumVal> >
> ReTw_custom_types;
}
IGL_INLINE TwType igl::anttweakbar::ReTwDefineEnum(
const char *name,
const TwEnumVal *enumValues,
unsigned int nbValues)
{
using namespace std;
// copy enum valus into vector
std::vector<TwEnumVal> enum_vals;
enum_vals.resize(nbValues);
for(unsigned int j = 0; j<nbValues;j++)
{
enum_vals[j] = enumValues[j];
}
TwType type = TwDefineEnum(name,enumValues,nbValues);
ReTw_custom_types[type] =
std::pair<const char *,std::vector<TwEnumVal> >(name,enum_vals);
return type;
}
IGL_INLINE TwType igl::anttweakbar::ReTwDefineEnumFromString(
const char * _Name,
const char * _EnumString)
{
// Taken directly from TwMgr.cpp, just replace TwDefineEnum with
// ReTwDefineEnum
using namespace std;
{
if (_EnumString == NULL)
return ReTwDefineEnum(_Name, NULL, 0);
// split enumString
stringstream EnumStream(_EnumString);
string Label;
vector<string> Labels;
while( getline(EnumStream, Label, ',') ) {
// trim Label
size_t Start = Label.find_first_not_of(" \n\r\t");
size_t End = Label.find_last_not_of(" \n\r\t");
if( Start==string::npos || End==string::npos )
Label = "";
else
Label = Label.substr(Start, (End-Start)+1);
// store Label
Labels.push_back(Label);
}
// create TwEnumVal array
vector<TwEnumVal> Vals(Labels.size());
for( int i=0; i<(int)Labels.size(); i++ )
{
Vals[i].Value = i;
// Wrong:
//Vals[i].Label = Labels[i].c_str();
// Allocate char on heap
// http://stackoverflow.com/a/10050258/148668
char * c_label = new char[Labels[i].length()+1];
std::strcpy(c_label, Labels[i].c_str());
Vals[i].Label = c_label;
}
const TwType type =
ReTwDefineEnum(_Name, Vals.empty() ?
NULL :
&(Vals[0]), (unsigned int)Vals.size());
return type;
}
}
namespace
{
struct ReTwTypeString
{
TwType type;
const char * type_str;
};
#define RETW_NUM_DEFAULT_TYPE_STRINGS 23
ReTwTypeString ReTwDefaultTypeStrings[RETW_NUM_DEFAULT_TYPE_STRINGS] =
{
{TW_TYPE_UNDEF,"TW_TYPE_UNDEF"},
{TW_TYPE_BOOLCPP,"TW_TYPE_BOOLCPP"},
{TW_TYPE_BOOL8,"TW_TYPE_BOOL8"},
{TW_TYPE_BOOL16,"TW_TYPE_BOOL16"},
{TW_TYPE_BOOL32,"TW_TYPE_BOOL32"},
{TW_TYPE_CHAR,"TW_TYPE_CHAR"},
{TW_TYPE_INT8,"TW_TYPE_INT8"},
{TW_TYPE_UINT8,"TW_TYPE_UINT8"},
{TW_TYPE_INT16,"TW_TYPE_INT16"},
{TW_TYPE_UINT16,"TW_TYPE_UINT16"},
{TW_TYPE_INT32,"TW_TYPE_INT32"},
{TW_TYPE_UINT32,"TW_TYPE_UINT32"},
{TW_TYPE_FLOAT,"TW_TYPE_FLOAT"},
{TW_TYPE_DOUBLE,"TW_TYPE_DOUBLE"},
{TW_TYPE_COLOR32,"TW_TYPE_COLOR32"},
{TW_TYPE_COLOR3F,"TW_TYPE_COLOR3F"},
{TW_TYPE_COLOR4F,"TW_TYPE_COLOR4F"},
{TW_TYPE_CDSTRING,"TW_TYPE_CDSTRING"},
{TW_TYPE_STDSTRING,"TW_TYPE_STDSTRING"},
{TW_TYPE_QUAT4F,"TW_TYPE_QUAT4F"},
{TW_TYPE_QUAT4D,"TW_TYPE_QUAT4D"},
{TW_TYPE_DIR3F,"TW_TYPE_DIR3F"},
{TW_TYPE_DIR3D,"TW_TYPE_DIR3D"}
};
}
IGL_INLINE igl::anttweakbar::ReTwBar::ReTwBar():
bar(NULL),
name(),
rw_items(),cb_items()
{
}
IGL_INLINE igl::anttweakbar::ReTwBar::ReTwBar(
const igl::anttweakbar::ReTwBar & that):
bar(that.bar),
name(that.name),
rw_items(that.rw_items),
cb_items(that.cb_items)
{
}
IGL_INLINE igl::anttweakbar::ReTwBar &
igl::anttweakbar::ReTwBar::operator=(const igl::anttweakbar::ReTwBar & that)
{
// check for self assignment
if(this != &that)
{
bar = that.bar;
rw_items = that.rw_items;
cb_items = that.cb_items;
}
return *this;
}
// BAR WRAPPERS
IGL_INLINE void igl::anttweakbar::ReTwBar::TwNewBar(const char * _name)
{
this->bar = ::TwNewBar(_name);
// Alec: This causes trouble (not sure why) in multiple applications
// (medit, puppet) Probably there is some sort of memory corrpution.
// this->name = _name;
// Suspiciously this also fails:
//this->name = "foobar";
}
IGL_INLINE int igl::anttweakbar::ReTwBar::TwAddVarRW(
const char *name,
TwType type,
void *var,
const char *def,
const bool record)
{
int ret = ::TwAddVarRW(this->bar,name,type,var,def);
if(ret && record)
{
rw_items.push_back(ReTwRWItem(name,type,var));
}
return ret;
}
IGL_INLINE int igl::anttweakbar::ReTwBar::TwAddVarCB(
const char *name,
TwType type,
TwSetVarCallback setCallback,
TwGetVarCallback getCallback,
void *clientData,
const char *def,
const bool record)
{
int ret =
::TwAddVarCB(this->bar,name,type,setCallback,getCallback,clientData,def);
if(ret && record)
{
cb_items.push_back(ReTwCBItem(name,type,setCallback,getCallback,clientData));
}
return ret;
}
IGL_INLINE int igl::anttweakbar::ReTwBar::TwAddVarRO(
const char *name,
TwType type,
void *var,
const char *def)
{
int ret = ::TwAddVarRO(this->bar,name,type,var,def);
// Read only variables are not recorded
//if(ret)
//{
// rw_items.push_back(ReTwRWItem(name,type,var));
//}
return ret;
}
IGL_INLINE int igl::anttweakbar::ReTwBar::TwAddButton(
const char *name,
TwButtonCallback buttonCallback,
void *clientData,
const char *def)
{
int ret =
::TwAddButton(this->bar,name,buttonCallback,clientData,def);
// buttons are not recorded
//if(ret)
//{
// cb_items.push_back(ReTwCBItem(name,type,setCallback,getCallback,clientData));
//}
return ret;
}
IGL_INLINE int igl::anttweakbar::ReTwBar::TwSetParam(
const char *varName,
const char *paramName,
TwParamValueType paramValueType,
unsigned int inValueCount,
const void *inValues)
{
// For now just pass these along
return
::TwSetParam(
this->bar,
varName,
paramName,
paramValueType,
inValueCount,
inValues);
}
IGL_INLINE int igl::anttweakbar::ReTwBar::TwGetParam(
const char *varName,
const char *paramName,
TwParamValueType paramValueType,
unsigned int outValueMaxCount,
void *outValues)
{
return
::TwGetParam(
this->bar,
varName,
paramName,
paramValueType,
outValueMaxCount,
outValues);
}
IGL_INLINE int igl::anttweakbar::ReTwBar::TwRefreshBar()
{
return ::TwRefreshBar(this->bar);
}
IGL_INLINE int igl::anttweakbar::ReTwBar::TwTerminate()
{
//std::cout<<"TwTerminate"<<std::endl;
int r = ::TwTerminate();
//std::cout<<" "<<r<<std::endl;
return r;
}
IGL_INLINE bool igl::anttweakbar::ReTwBar::save(const char *file_name)
{
FILE * fp;
if(file_name == NULL)
{
fp = stdout;
}else
{
fp = fopen(file_name,"w");
}
if(fp == NULL)
{
printf("ERROR: not able to open %s for writing...\n",file_name);
return false;
}
// Print all RW variables
for(
std::vector<ReTwRWItem>::iterator it = rw_items.begin();
it != rw_items.end();
it++)
{
std::string s = (*it).name;
const char * name = s.c_str();
TwType type = (*it).type;
void * var = (*it).var;
fprintf(fp,"%s: %s\n",
name,
get_value_as_string(var,type).c_str());
}
char var[REANTTWEAKBAR_MAX_CB_VAR_SIZE];
// Print all CB variables
for(
std::vector<ReTwCBItem>::iterator it = cb_items.begin();
it != cb_items.end();
it++)
{
const char * name = it->name.c_str();
TwType type = it->type;
//TwSetVarCallback setCallback = it->setCallback;
TwGetVarCallback getCallback = it->getCallback;
void * clientData = it->clientData;
// I'm not sure how to do what I want to do. getCallback needs to be sure
// that it can write to var. So var needs to point to a valid and big
// enough chunk of memory
getCallback(var,clientData);
fprintf(fp,"%s: %s\n",
name,
get_value_as_string(var,type).c_str());
}
fprintf(fp,"\n");
if(file_name != NULL)
{
fclose(fp);
}
// everything succeeded
return true;
}
IGL_INLINE std::string igl::anttweakbar::ReTwBar::get_value_as_string(
void * var,
TwType type)
{
std::stringstream sstr;
switch(type)
{
case TW_TYPE_BOOLCPP:
{
sstr << "TW_TYPE_BOOLCPP" << " ";
sstr << *(static_cast<bool*>(var));
break;
}
case TW_TYPE_QUAT4D:
{
sstr << "TW_TYPE_QUAT4D" << " ";
// Q: Why does casting to double* work? shouldn't I have to cast to
// double**?
double * q = static_cast<double*>(var);
sstr << std::setprecision(15) << q[0] << " " << q[1] << " " << q[2] << " " << q[3];
break;
}
case TW_TYPE_QUAT4F:
{
sstr << "TW_TYPE_QUAT4F" << " ";
// Q: Why does casting to float* work? shouldn't I have to cast to
// float**?
float * q = static_cast<float*>(var);
sstr << q[0] << " " << q[1] << " " << q[2] << " " << q[3];
break;
}
case TW_TYPE_COLOR4F:
{
sstr << "TW_TYPE_COLOR4F" << " ";
float * c = static_cast<float*>(var);
sstr << c[0] << " " << c[1] << " " << c[2] << " " << c[3];
break;
}
case TW_TYPE_COLOR3F:
{
sstr << "TW_TYPE_COLOR3F" << " ";
float * c = static_cast<float*>(var);
sstr << c[0] << " " << c[1] << " " << c[2];
break;
}
case TW_TYPE_DIR3D:
{
sstr << "TW_TYPE_DIR3D" << " ";
double * d = static_cast<double*>(var);
sstr << std::setprecision(15) << d[0] << " " << d[1] << " " << d[2];
break;
}
case TW_TYPE_DIR3F:
{
sstr << "TW_TYPE_DIR3F" << " ";
float * d = static_cast<float*>(var);
sstr << d[0] << " " << d[1] << " " << d[2];
break;
}
case TW_TYPE_BOOL32:
{
sstr << "TW_TYPE_BOOL32" << " ";
sstr << *(static_cast<int*>(var));
break;
}
case TW_TYPE_UINT8:
{
sstr << "TW_TYPE_UINT8" << " ";
// Cast to int so that it's human readable
sstr << (int)*(static_cast<unsigned char*>(var));
break;
}
case TW_TYPE_INT32:
{
sstr << "TW_TYPE_INT32" << " ";
sstr << *(static_cast<int*>(var));
break;
}
case TW_TYPE_UINT32:
{
sstr << "TW_TYPE_UINT32" << " ";
sstr << *(static_cast<unsigned int*>(var));
break;
}
case TW_TYPE_FLOAT:
{
sstr << "TW_TYPE_FLOAT" << " ";
sstr << *(static_cast<float*>(var));
break;
}
case TW_TYPE_DOUBLE:
{
sstr << "TW_TYPE_DOUBLE" << " ";
sstr << std::setprecision(15) << *(static_cast<double*>(var));
break;
}
case TW_TYPE_STDSTRING:
{
sstr << "TW_TYPE_STDSTRING" << " ";
std::string *destPtr = static_cast<std::string *>(var);
sstr << destPtr->c_str();
break;
}
default:
{
using namespace std;
std::map<TwType,std::pair<const char *,std::vector<TwEnumVal> > >::const_iterator iter =
ReTw_custom_types.find(type);
if(iter != ReTw_custom_types.end())
{
sstr << (*iter).second.first << " ";
int enum_val = *(static_cast<int*>(var));
// try find display name for enum value
std::vector<TwEnumVal>::const_iterator eit = (*iter).second.second.begin();
bool found = false;
for(;eit<(*iter).second.second.end();eit++)
{
if(enum_val == eit->Value)
{
sstr << eit->Label;
found = true;
break;
}
}
if(!found)
{
sstr << "ERROR_ENUM_VALUE_NOT_DEFINED";
}
}else
{
sstr << "ERROR_TYPE_NOT_SUPPORTED";
}
break;
}
}
return sstr.str();
}
IGL_INLINE bool igl::anttweakbar::ReTwBar::load(const char *file_name)
{
FILE * fp;
fp = fopen(file_name,"r");
if(fp == NULL)
{
printf("ERROR: not able to open %s for reading...\n",file_name);
return false;
}
// go through file line by line
char line[REANTTWEAKBAR_MAX_LINE];
bool still_comments;
char name[REANTTWEAKBAR_MAX_WORD];
char type_str[REANTTWEAKBAR_MAX_WORD];
char value_str[REANTTWEAKBAR_MAX_WORD];
// line number
int j = 0;
bool finished = false;
while(true)
{
// Eat comments
still_comments = true;
while(still_comments)
{
if(fgets(line,REANTTWEAKBAR_MAX_LINE,fp) == NULL)
{
finished = true;
break;
}
// Blank lines and lines that begin with # are comments
still_comments = (line[0] == '#' || line[0] == '\n');
j++;
}
if(finished)
{
break;
}
sscanf(line,"%[^:]: %s %[^\n]",name,type_str,value_str);
//printf("%s: %s %s\n",name, type_str,value_str);
TwType type;
if(!type_from_string(type_str,type))
{
printf("ERROR: %s type not found... Skipping...\n",type_str);
continue;
}
set_value_from_string(name,type,value_str);
}
fclose(fp);
// everything succeeded
return true;
}
IGL_INLINE bool igl::anttweakbar::ReTwBar::type_from_string(
const char *type_str, TwType & type)
{
// first check default types
for(int j = 0; j < RETW_NUM_DEFAULT_TYPE_STRINGS; j++)
{
if(strcmp(type_str,ReTwDefaultTypeStrings[j].type_str) == 0)
{
type = ReTwDefaultTypeStrings[j].type;
return true;
break;
}
}
// then check custom types
std::map<
TwType,std::pair<const char *,std::vector<TwEnumVal> >
>::const_iterator iter =
ReTw_custom_types.begin();
for(;iter != ReTw_custom_types.end(); iter++)
{
if(strcmp((*iter).second.first,type_str)==0)
{
type = (*iter).first;
return true;
}
}
return false;
}
bool igl::anttweakbar::ReTwBar::set_value_from_string(
const char * name,
TwType type,
const char * value_str)
{
void * value = NULL;
// possible value slots
int i;
float v;
double dv;
float f[4];
double d[4];
bool b;
unsigned int u;
unsigned char uc;
std::string s;
// First try to get value from default types
switch(type)
{
case TW_TYPE_BOOLCPP:
{
int ib;
if(sscanf(value_str," %d",&ib) == 1)
{
b = ib!=0;
value = &b;
}else
{
printf("ERROR: Bad value format...\n");
return false;
}
break;
}
case TW_TYPE_QUAT4D:
//case TW_TYPE_COLOR4D:
{
if(sscanf(value_str," %lf %lf %lf %lf",&d[0],&d[1],&d[2],&d[3]) == 4)
{
value = &d;
}else
{
printf("ERROR: Bad value format...\n");
return false;
}
break;
}
case TW_TYPE_QUAT4F:
case TW_TYPE_COLOR4F:
{
if(sscanf(value_str," %f %f %f %f",&f[0],&f[1],&f[2],&f[3]) == 4)
{
value = &f;
}else
{
printf("ERROR: Bad value format...\n");
return false;
}
break;
}
//case TW_TYPE_COLOR3D:
case TW_TYPE_DIR3D:
{
if(sscanf(value_str," %lf %lf %lf",&d[0],&d[1],&d[2]) == 3)
{
value = &d;
}else
{
printf("ERROR: Bad value format...\n");
return false;
}
break;
}
case TW_TYPE_COLOR3F:
case TW_TYPE_DIR3F:
{
if(sscanf(value_str," %f %f %f",&f[0],&f[1],&f[2]) == 3)
{
value = &f;
}else
{
printf("ERROR: Bad value format...\n");
return false;
}
break;
}
case TW_TYPE_UINT8:
{
if(sscanf(value_str," %d",&i) == 1)
{
// Cast to unsigned char
uc = (unsigned char) i;
value = &uc;
}else
{
printf("ERROR: Bad value format...\n");
return false;
}
break;
}
case TW_TYPE_BOOL32:
case TW_TYPE_INT32:
{
if(sscanf(value_str," %d",&i) == 1)
{
value = &i;
}else
{
printf("ERROR: Bad value format...\n");
return false;
}
break;
}
case TW_TYPE_UINT32:
{
if(sscanf(value_str," %u",&u) == 1)
{
value = &u;
}else
{
printf("ERROR: Bad value format...\n");
return false;
}
break;
}
case TW_TYPE_FLOAT:
{
if(sscanf(value_str," %f",&v) == 1)
{
value = &v;
}else
{
printf("ERROR: Bad value format...\n");
return false;
}
break;
}
case TW_TYPE_DOUBLE:
{
if(sscanf(value_str," %lf",&dv) == 1)
{
value = &dv;
}else
{
printf("ERROR: Bad value format...\n");
return false;
}
break;
}
case TW_TYPE_STDSTRING:
{
s = value_str;
value = &s;
break;
}
default:
// Try to find type in custom enum types
std::map<TwType,std::pair<const char *,std::vector<TwEnumVal> > >::const_iterator iter =
ReTw_custom_types.find(type);
if(iter != ReTw_custom_types.end())
{
std::vector<TwEnumVal>::const_iterator eit = (*iter).second.second.begin();
bool found = false;
for(;eit<(*iter).second.second.end();eit++)
{
if(strcmp(value_str,eit->Label) == 0)
{
i = eit->Value;
value = &i;
found = true;
break;
}
}
if(!found)
{
printf("ERROR_ENUM_VALUE_NOT_DEFINED");
}
}else
{
printf("ERROR_TYPE_NOT_SUPPORTED\n");
}
break;
}
// Find variable based on name
// First look in RW items
bool item_found = false;
for(
std::vector<ReTwRWItem>::iterator it = rw_items.begin();
it != rw_items.end();
it++)
{
if(it->name == name)
{
void * var = it->var;
switch(type)
{
case TW_TYPE_BOOLCPP:
{
bool * bvar = static_cast<bool*>(var);
bool * bvalue = static_cast<bool*>(value);
*bvar = *bvalue;
break;
}
case TW_TYPE_QUAT4D:
//case TW_TYPE_COLOR4D:
{
double * dvar = static_cast<double*>(var);
double * dvalue = static_cast<double*>(value);
dvar[0] = dvalue[0];
dvar[1] = dvalue[1];
dvar[2] = dvalue[2];
dvar[3] = dvalue[3];
break;
}
case TW_TYPE_QUAT4F:
case TW_TYPE_COLOR4F:
{
float * fvar = static_cast<float*>(var);
float * fvalue = static_cast<float*>(value);
fvar[0] = fvalue[0];
fvar[1] = fvalue[1];
fvar[2] = fvalue[2];
fvar[3] = fvalue[3];
break;
}
//case TW_TYPE_COLOR3D:
case TW_TYPE_DIR3D:
{
double * dvar = static_cast<double*>(var);
double * dvalue = static_cast<double*>(value);
dvar[0] = dvalue[0];
dvar[1] = dvalue[1];
dvar[2] = dvalue[2];
break;
}
case TW_TYPE_COLOR3F:
case TW_TYPE_DIR3F:
{
float * fvar = static_cast<float*>(var);
float * fvalue = static_cast<float*>(value);
fvar[0] = fvalue[0];
fvar[1] = fvalue[1];
fvar[2] = fvalue[2];
break;
}
case TW_TYPE_UINT8:
{
unsigned char * ucvar = static_cast<unsigned char*>(var);
unsigned char * ucvalue = static_cast<unsigned char*>(value);
*ucvar = *ucvalue;
break;
}
case TW_TYPE_BOOL32:
case TW_TYPE_INT32:
{
int * ivar = static_cast<int*>(var);
int * ivalue = static_cast<int*>(value);
*ivar = *ivalue;
break;
}
case TW_TYPE_UINT32:
{
unsigned int * uvar = static_cast<unsigned int*>(var);
unsigned int * uvalue = static_cast<unsigned int*>(value);
*uvar = *uvalue;
break;
}
case TW_TYPE_FLOAT:
{
float * fvar = static_cast<float*>(var);
float * fvalue = static_cast<float*>(value);
*fvar = *fvalue;
break;
}
case TW_TYPE_DOUBLE:
{
double * dvar = static_cast<double*>(var);
double * fvalue = static_cast<double*>(value);
*dvar = *fvalue;
break;
}
case TW_TYPE_STDSTRING:
{
std::string * svar = static_cast<std::string*>(var);
std::string * svalue = static_cast<std::string*>(value);
*svar = *svalue;
break;
}
default:
// Try to find type in custom enum types
std::map<TwType,std::pair<const char *,std::vector<TwEnumVal> > >::iterator iter =
ReTw_custom_types.find(type);
if(iter != ReTw_custom_types.end())
{
int * ivar = static_cast<int*>(var);
std::vector<TwEnumVal>::iterator eit = (*iter).second.second.begin();
bool found = false;
for(;eit<(*iter).second.second.end();eit++)
{
if(strcmp(value_str,eit->Label) == 0)
{
*ivar = eit->Value;
found = true;
break;
}
}
if(!found)
{
printf("ERROR_ENUM_VALUE_NOT_DEFINED");
}
}else
{
printf("ERROR_TYPE_NOT_SUPPORTED\n");
}
break;
}
item_found = true;
break;
}
}
// Try looking in CB items
if(!item_found)
{
for(
std::vector<ReTwCBItem>::iterator it = cb_items.begin();
it != cb_items.end();
it++)
{
if(it->name==name)
{
it->setCallback(value,it->clientData);
item_found = true;
break;
}
}
}
if(!item_found)
{
printf("ERROR: item '%s' not found\n",name);
}
return true;
}
IGL_INLINE const std::vector<igl::anttweakbar::ReTwRWItem> &
igl::anttweakbar::ReTwBar::get_rw_items()
{
return rw_items;
}
IGL_INLINE const std::vector<igl::anttweakbar::ReTwCBItem> &
igl::anttweakbar::ReTwBar::get_cb_items()
{
return cb_items;
}

View File

@@ -1,286 +0,0 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ANTTWEAKBAR_REANTTWEAKBAR_H
#define IGL_ANTTWEAKBAR_REANTTWEAKBAR_H
#include "../igl_inline.h"
// ReAntTweakBar is a minimal wrapper for the AntTweakBar library that allows
// "bars" to be saved and load from disk. Changing your existing app that uses
// AntTweakBar to use ReAntTweakBar is trivial.
//
// Many (but not all) variable types are supported. I'll try to keep track them
// here:
// TW_TYPE_BOOLCPP
// TW_TYPE_QUAT4F
// TW_TYPE_QUAT4D
// TW_TYPE_COLOR4F
// TW_TYPE_COLOR4D
// TW_TYPE_COLOR3F
// TW_TYPE_DIR3F
// TW_TYPE_DIR3D
// TW_TYPE_BOOL32
// TW_TYPE_INT32
// TW_TYPE_UINT32
// TW_TYPE_FLOAT
// TW_TYPE_DOUBLE
// TW_TYPE_UINT8
// and
// custom TwTypes made with TwDefineEnum
//
// I'm working on adding the rest on an as-needed basis. Adding a new type only
// requires changes in a few places...
//
//
//
// This allows the user to have a non-global, static installation of
// AntTweakBar
#include <AntTweakBar.h>
// Instead of including AntTweakBar.h, just define the necessary types
// Types used:
// - TwType
// - TwEnumVal
// - TwSetVarCallback
// - TwGetVarCallback
// - TwBar
// - TwButtonCallback
#include <vector>
#include <string>
#define REANTTWEAKBAR_MAX_CB_VAR_SIZE 1000
// Max line size for reading files
#define REANTTWEAKBAR_MAX_LINE 1000
#define REANTTWEAKBAR_MAX_WORD 100
namespace igl
{
namespace anttweakbar
{
TwType ReTwDefineEnum(
const char *name,
const TwEnumVal *enumValues,
unsigned int nbValues);
TwType ReTwDefineEnumFromString(const char * name,const char * enumString);
struct ReTwRWItem
{
//const char * name;
std::string name;
TwType type;
void * var;
// Default constructor
IGL_INLINE ReTwRWItem(
const std::string _name,
TwType _type,
void *_var):
name(_name),
type(_type),
var(_var)
{
}
// Shallow copy constructor
// I solemnly swear it's OK to copy var this way
// Q: Is it really?
IGL_INLINE ReTwRWItem(const ReTwRWItem & that):
name(that.name),
type(that.type),
var(that.var)
{
}
// Shallow assignment
// I solemnly swear it's OK to copy var this way
IGL_INLINE ReTwRWItem & operator=(const ReTwRWItem & that)
{
if(this != &that)
{
this->name = that.name;
this->type = that.type;
this->var = that.var;
}
return *this;
}
};
struct ReTwCBItem
{
//const char * name;
std::string name;
TwType type;
TwSetVarCallback setCallback;
TwGetVarCallback getCallback;
void * clientData;
// Default constructor
IGL_INLINE ReTwCBItem(
const std::string _name,
TwType _type,
TwSetVarCallback _setCallback,
TwGetVarCallback _getCallback,
void * _clientData):
name(_name),
type(_type),
setCallback(_setCallback),
getCallback(_getCallback),
clientData(_clientData)
{
}
// Shallow copy
// I solemnly swear it's OK to copy clientData this way
IGL_INLINE ReTwCBItem(const ReTwCBItem & that):
name(that.name),
type(that.type),
setCallback(that.setCallback),
getCallback(that.getCallback),
clientData(that.clientData)
{
}
// Shallow assignment
// I solemnly swear it's OK to copy clientData this way
IGL_INLINE ReTwCBItem & operator=(const ReTwCBItem & that)
{
if(this != &that)
{
name = that.name;
type = that.type;
setCallback = that.setCallback;
getCallback = that.getCallback;
clientData = that.clientData;
}
return *this;
}
};
class ReTwBar
{
// VARIABLES
// Should be private, but seeing as I'm not going to implement all of the
// AntTweakBar public functions right away, I'll expose this so that at
// anytime AntTweakBar functions can be called directly on the bar
public:
TwBar * bar;
std::string name;
protected:
std::vector<ReTwRWItem> rw_items;
std::vector<ReTwCBItem> cb_items;
public:
// Default constructor with explicit initialization
IGL_INLINE ReTwBar();
private:
// Copy constructor does shallow copy
IGL_INLINE ReTwBar(const ReTwBar & that);
// Assignment operator does shallow assignment
IGL_INLINE ReTwBar &operator=(const ReTwBar & that);
// WRAPPERS FOR ANTTWEAKBAR FUNCTIONS
public:
IGL_INLINE void TwNewBar(const char *_name);
IGL_INLINE int TwAddVarRW(
const char *name,
TwType type,
void *var,
const char *def,
const bool record=true);
IGL_INLINE int TwAddVarCB(
const char *name,
TwType type,
TwSetVarCallback setCallback,
TwGetVarCallback getCallback,
void *clientData,
const char *def,
const bool record=true);
// Wrappers for convenience (not recorded, just passed on)
IGL_INLINE int TwAddVarRO(const char *name, TwType type, void *var, const char *def);
IGL_INLINE int TwAddButton(
const char *name,
TwButtonCallback buttonCallback,
void *clientData,
const char *def);
IGL_INLINE int TwSetParam(
const char *varName,
const char *paramName,
TwParamValueType paramValueType,
unsigned int inValueCount,
const void *inValues);
IGL_INLINE int TwGetParam(
const char *varName,
const char *paramName,
TwParamValueType paramValueType,
unsigned int outValueMaxCount,
void *outValues);
IGL_INLINE int TwRefreshBar();
IGL_INLINE int TwTerminate();
// IO FUNCTIONS
public:
// Save current items to file
// Input:
// file_name name of file to save data to, can be null which means print
// to stdout
// Return:
// true only if there were no (fatal) errors
IGL_INLINE bool save(const char *file_name);
std::string get_value_as_string(
void * var,
TwType type);
// Load into current items from file
// Input:
// file_name name of input file to load
// Return:
// true only if there were no (fatal) errors
IGL_INLINE bool load(const char *file_name);
// Get TwType from string
// Input
// type_str string of type
// Output
// type TwType converted from string
// Returns
// true only if string matched a valid type
IGL_INLINE bool type_from_string(const char *type_str, TwType & type);
// I realize that I mix std::string and const char * all over the place.
// What can you do...
IGL_INLINE bool set_value_from_string(
const char * name,
TwType type,
const char * value_str);
IGL_INLINE const std::vector<ReTwRWItem> & get_rw_items();
IGL_INLINE const std::vector<ReTwCBItem> & get_cb_items();
};
}
}
// List of TwBar functions
//TW_API TwBar * TW_CALL TwNewBar(const char *barName);
//TW_API int TW_CALL TwDeleteBar(TwBar *bar);
//TW_API int TW_CALL TwDeleteAllBars();
//TW_API int TW_CALL TwSetTopBar(const TwBar *bar);
//TW_API TwBar * TW_CALL TwGetTopBar();
//TW_API int TW_CALL TwSetBottomBar(const TwBar *bar);
//TW_API TwBar * TW_CALL TwGetBottomBar();
//TW_API const char * TW_CALL TwGetBarName(TwBar *bar);
//TW_API int TW_CALL TwGetBarCount();
//TW_API TwBar * TW_CALL TwGetBarByIndex(int barIndex);
//TW_API TwBar * TW_CALL TwGetBarByName(const char *barName);
//TW_API int TW_CALL TwRefreshBar(TwBar *bar);
//TW_API int TW_CALL TwTerminate();
//
//TW_API int TW_CALL TwAddVarRW(TwBar *bar, const char *name, TwType type, void *var, const char *def);
//TW_API int TW_CALL TwAddVarRO(TwBar *bar, const char *name, TwType type, const void *var, const char *def);
//TW_API int TW_CALL TwAddVarCB(TwBar *bar, const char *name, TwType type, TwSetVarCallback setCallback, TwGetVarCallback getCallback, void *clientData, const char *def);
//TW_API int TW_CALL TwAddButton(TwBar *bar, const char *name, TwButtonCallback callback, void *clientData, const char *def);
//TW_API int TW_CALL TwAddSeparator(TwBar *bar, const char *name, const char *def);
//TW_API int TW_CALL TwRemoveVar(TwBar *bar, const char *name);
//TW_API int TW_CALL TwRemoveAllVars(TwBar *bar);
// Until AntTweakBar dependency folder exists, this is header-only
#ifndef IGL_STATIC_LIBRARY
# include "ReAntTweakBar.cpp"
#endif
#endif

View File

@@ -1,81 +0,0 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "cocoa_key_to_anttweakbar_key.h"
#include <AntTweakBar.h>
IGL_INLINE int igl::anttweakbar::cocoa_key_to_anttweakbar_key(int key)
{
// I've left commented the AntTweakBar key codes that correspond to keys I
// don't have on my keyboard. Please fill this in if you have those keys
switch(key)
{
case 127:
return TW_KEY_BACKSPACE;
case 9:
return TW_KEY_TAB;
//TW_KEY_CLEAR = 0x0c,
case 3://ENTER
case 13:
return TW_KEY_RETURN;
case 27:
return TW_KEY_ESCAPE;
case 32:
return TW_KEY_SPACE;
// IN A GLUT APP 40 is (
//case 40:
case 63272:
return TW_KEY_DELETE;
case 63232:
return TW_KEY_UP;
case 63233:
return TW_KEY_DOWN;
case 63235:
return TW_KEY_RIGHT;
case 63234:
return TW_KEY_LEFT;
//TW_KEY_INSERT,
//TW_KEY_HOME,
//TW_KEY_END,
//TW_KEY_PAGE_UP,
//TW_KEY_PAGE_DOWN,
case 63236:
return TW_KEY_F1;
case 63237:
return TW_KEY_F2;
case 63238:
return TW_KEY_F3;
case 63239:
return TW_KEY_F4;
case 63240:
return TW_KEY_F5;
case 63241:
return TW_KEY_F6;
case 63242:
return TW_KEY_F7;
case 63243:
return TW_KEY_F8;
case 63244:
return TW_KEY_F9;
case 63245:
return TW_KEY_F10;
case 63246:
return TW_KEY_F11;
case 63247:
return TW_KEY_F12;
case 63248:
return TW_KEY_F13;
case 63249:
return TW_KEY_F14;
case 63250:
return TW_KEY_F15;
default:
break;
}
return key;
}

View File

@@ -1,31 +0,0 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ANTTWEAKBAR_COCOA_KEY_TO_ANTTWEAKBAR_KEY_H
#define IGL_ANTTWEAKBAR_COCOA_KEY_TO_ANTTWEAKBAR_KEY_H
#include "../igl_inline.h"
namespace igl
{
namespace anttweakbar
{
// Convert an unsigned char (like that from Cocoa apps) to AntTweakBar key
// code.
// See also: TranslateKey() in TwMgr.cpp in AntTweakBar source
// Inputs:
// key unsigned char key from keyboard
// Returns int of new key code
IGL_INLINE int cocoa_key_to_anttweakbar_key(int key);
}
}
#ifndef IGL_STATIC_LIBRARY
# include "cocoa_key_to_anttweakbar_key.cpp"
#endif
#endif

View File

@@ -12,16 +12,15 @@
#include <Eigen/Sparse>
namespace igl
{
// For Dense matrices use: A.rowwise().any() or A.colwise().any()
//
// Inputs:
// A m by n sparse matrix
// dim dimension along which to check for any (1 or 2)
// Output:
// B n-long vector (if dim == 1)
// or
// B m-long vector (if dim == 2)
//
/// Check whether any values are logically true along a dimension.
///
/// \note Dense matrices use: A.rowwise().any() or A.colwise().any()
///
/// @param[in] A m by n sparse matrix
/// @param[in] dim dimension along which to check for any (1 or 2)
/// @param[out] B n-long vector (if dim == 1)
/// or m-long vector (if dim == 2)
///
template <typename AType, typename DerivedB>
IGL_INLINE void any(
const Eigen::SparseMatrix<AType> & A,

View File

@@ -1,20 +0,0 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "any_of.h"
#include <Eigen/Core>
template <typename Mat>
IGL_INLINE bool igl::any_of(const Mat & S)
{
return std::any_of(S.data(),S.data()+S.size(),[](bool s){return s;});
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template bool igl::any_of<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::Matrix<int, -1, 1, 0, -1, 1> const&);
#endif

View File

@@ -1,26 +0,0 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ANY_OF_H
#define IGL_ANY_OF_H
#include "igl_inline.h"
namespace igl
{
// Wrapper for STL `any_of` for matrix types
//
// Inputs:
// S matrix
// Returns whether any entries are true
//
// Seems that Eigen (now) implements this for `Eigen::Array`
template <typename Mat>
IGL_INLINE bool any_of(const Mat & S);
}
#ifndef IGL_STATIC_LIBRARY
# include "any_of.cpp"
#endif
#endif

View File

@@ -14,7 +14,6 @@
#include "speye.h"
#include "mode.h"
#include "project_isometrically_to_plane.h"
#include "slice.h"
#include "arap_rhs.h"
#include "repdiag.h"
#include "columnize.h"
@@ -22,20 +21,24 @@
#include <cassert>
#include <iostream>
template <typename Scalar>
using MatrixXX = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;
template <
typename DerivedV,
typename DerivedF,
typename Derivedb>
IGL_INLINE bool igl::arap_precomputation(
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedF> & F,
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F,
const int dim,
const Eigen::PlainObjectBase<Derivedb> & b,
const Eigen::MatrixBase<Derivedb> & b,
ARAPData & data)
{
using namespace std;
using namespace Eigen;
typedef typename DerivedV::Scalar Scalar;
typedef typename DerivedF::Scalar Integer;
// number of vertices
const int n = V.rows();
data.n = n;
@@ -55,8 +58,8 @@ IGL_INLINE bool igl::arap_precomputation(
assert(data.dim <= V.cols() && "solve dim should be <= embedding");
bool flat = (V.cols() - data.dim)==1;
DerivedV plane_V;
DerivedF plane_F;
MatrixXX<Scalar> plane_V;
MatrixXX<Integer> plane_F;
typedef SparseMatrix<Scalar> SparseMatrixS;
SparseMatrixS ref_map,ref_map_dim;
if(flat)
@@ -64,8 +67,8 @@ IGL_INLINE bool igl::arap_precomputation(
project_isometrically_to_plane(V,F,plane_V,plane_F,ref_map);
repdiag(ref_map,dim,ref_map_dim);
}
const PlainObjectBase<DerivedV>& ref_V = (flat?plane_V:V);
const PlainObjectBase<DerivedF>& ref_F = (flat?plane_F:F);
const MatrixXX<Scalar>& ref_V = (flat?plane_V:V);
const MatrixXX<Integer>& ref_F = (flat?plane_F:F);
SparseMatrixS L;
cotmatrix(V,F,L);
@@ -122,9 +125,7 @@ IGL_INLINE bool igl::arap_precomputation(
MatrixXi GF(F.rows(),F.cols());
for(int j = 0;j<F.cols();j++)
{
Matrix<int,Eigen::Dynamic,1> GFj;
slice(data.G,F.col(j),GFj);
GF.col(j) = GFj;
GF.col(j) = data.G(F.col(j));
}
mode<int>(GF,2,GG);
data.G=GG;
@@ -169,30 +170,20 @@ template <
typename Derivedbc,
typename DerivedU>
IGL_INLINE bool igl::arap_solve(
const Eigen::PlainObjectBase<Derivedbc> & bc,
const Eigen::MatrixBase<Derivedbc> & bc,
ARAPData & data,
Eigen::PlainObjectBase<DerivedU> & U)
Eigen::MatrixBase<DerivedU> & U)
{
using namespace Eigen;
using namespace std;
assert(data.b.size() == bc.rows());
if(bc.size() > 0)
{
assert(U.size() != 0 && "U cannot be empty");
assert(U.cols() == data.dim && "U.cols() match data.dim");
if (bc.size() > 0) {
assert(bc.cols() == data.dim && "bc.cols() match data.dim");
}
const int n = data.n;
int iter = 0;
if(U.size() == 0)
{
// terrible initial guess.. should at least copy input mesh
#ifndef NDEBUG
cerr<<"arap_solve: Using terrible initial guess for U. Try U = V."<<endl;
#endif
U = MatrixXd::Zero(data.n,data.dim);
}else
{
assert(U.cols() == data.dim && "U.cols() match data.dim");
}
// changes each arap iteration
MatrixXd U_prev = U;
// doesn't change for fixed with_dynamics timestep
@@ -307,6 +298,6 @@ IGL_INLINE bool igl::arap_solve(
}
#ifdef IGL_STATIC_LIBRARY
template bool igl::arap_solve<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, igl::ARAPData&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template bool igl::arap_precomputation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, igl::ARAPData&);
template bool igl::arap_solve<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, igl::ARAPData&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template bool igl::arap_precomputation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, igl::ARAPData&);
#endif

View File

@@ -15,36 +15,41 @@
namespace igl
{
/// Parameters and precomputed values for arap solver.
///
/// \fileinfo
struct ARAPData
{
// n #V
// G #V list of group indices (1 to k) for each vertex, such that vertex i
// is assigned to group G(i)
// energy type of energy to use
// with_dynamics whether using dynamics (need to call arap_precomputation
// after changing)
// f_ext #V by dim list of external forces
// vel #V by dim list of velocities
// h dynamics time step
// ym ~Young's modulus smaller is softer, larger is more rigid/stiff
// max_iter maximum inner iterations
// K rhs pre-multiplier
// M mass matrix
// solver_data quadratic solver data
// b list of boundary indices into V
// dim dimension being used for solving
/// #V size of mesh
int n;
/// #V list of group indices (1 to k) for each vertex, such that vertex i
/// is assigned to group G(i)
Eigen::VectorXi G;
/// type of energy to use
ARAPEnergyType energy;
/// whether using dynamics (need to call arap_precomputation after changing)
bool with_dynamics;
Eigen::MatrixXd f_ext,vel;
/// #V by dim list of external forces
Eigen::MatrixXd f_ext;
/// #V by dim list of velocities
Eigen::MatrixXd vel;
/// dynamics time step
double h;
/// "Young's modulus" smaller is softer, larger is more rigid/stiff
double ym;
/// maximum inner iterations
int max_iter;
Eigen::SparseMatrix<double> K,M;
/// @private rhs pre-multiplier
Eigen::SparseMatrix<double> K;
/// @private mass matrix
Eigen::SparseMatrix<double> M;
/// @private covariance scatter matrix
Eigen::SparseMatrix<double> CSM;
/// @private quadratic solver data
min_quad_with_fixed_data<double> solver_data;
/// @private list of boundary indices into V
Eigen::VectorXi b;
/// @private dimension being used for solving
int dim;
ARAPData():
n(0),
@@ -64,37 +69,51 @@ namespace igl
};
};
// Compute necessary information to start using an ARAP deformation
//
// Inputs:
// V #V by dim list of mesh positions
// F #F by simplex-size list of triangle|tet indices into V
// dim dimension being used at solve time. For deformation usually dim =
// V.cols(), for surface parameterization V.cols() = 3 and dim = 2
// b #b list of "boundary" fixed vertex indices into V
// Outputs:
// data struct containing necessary precomputation
/// Compute necessary information to start using an ARAP deformation using
/// local-global solver as described in "As-rigid-as-possible surface
/// modeling" [Sorkine and Alexa 2007].
///
/// @param[in] V #V by dim list of mesh positions
/// @param[in] F #F by simplex-size list of triangle|tet indices into V
/// @param[in] dim dimension being used at solve time. For deformation usually dim =
/// V.cols(), for surface parameterization V.cols() = 3 and dim = 2
/// @param[in] b #b list of "boundary" fixed vertex indices into V
/// @param[out] data struct containing necessary precomputation
/// @return whether initialization succeeded
///
/// \fileinfo
template <
typename DerivedV,
typename DerivedF,
typename Derivedb>
IGL_INLINE bool arap_precomputation(
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedF> & F,
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F,
const int dim,
const Eigen::PlainObjectBase<Derivedb> & b,
const Eigen::MatrixBase<Derivedb> & b,
ARAPData & data);
// Inputs:
// bc #b by dim list of boundary conditions
// data struct containing necessary precomputation and parameters
// U #V by dim initial guess
/// Conduct arap solve.
///
/// @param[in] bc #b by dim list of boundary conditions
/// @param[in] data struct containing necessary precomputation and parameters
/// @param[in,out] U #V by dim initial guess
///
/// \fileinfo
///
/// \note While the libigl guidelines require outputs to be of type
/// PlainObjectBase so that the user does not need to worry about allocating
/// memory for the output, in this case, the user is required to give an initial
/// guess and hence fix the size of the problem domain.
/// Taking a reference to MatrixBase in this case thus allows the user to provide e.g.
/// a map to the position data, allowing seamless interoperability with user-defined
/// datastructures without requiring a copy.
template <
typename Derivedbc,
typename DerivedU>
IGL_INLINE bool arap_solve(
const Eigen::PlainObjectBase<Derivedbc> & bc,
const Eigen::MatrixBase<Derivedbc> & bc,
ARAPData & data,
Eigen::PlainObjectBase<DerivedU> & U);
Eigen::MatrixBase<DerivedU> & U);
};
#ifndef IGL_STATIC_LIBRARY

View File

@@ -6,6 +6,7 @@
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "arap_dof.h"
#include "IGL_ASSERT.h"
#include "cotmatrix.h"
#include "massmatrix.h"
@@ -25,15 +26,36 @@
#include "verbose.h"
#include "print_ijv.h"
#include "get_seconds_hires.h"
//#include "MKLEigenInterface.h"
#include "min_quad_dense.h"
#include "kkt_inverse.h"
#include "get_seconds.h"
#include "columnize.h"
#include <type_traits>
// defined if no early exit is supported, i.e., always take a fixed number of iterations
#define IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
// To avoid putting _any_ dense slices in the static library use a work around
// so that we can slice LbsMatrixType as sparse or dense below.
#if __cplusplus < 201703L
template <typename Mat, bool IsSparse> struct arap_dof_slice_helper;
template <typename Mat> struct arap_dof_slice_helper<Mat,true>
{
static void slice(const Mat & A, const Eigen::VectorXi & I, const Eigen::VectorXi & J, Mat & B)
{
static_assert(std::is_base_of<Eigen::SparseMatrixBase<Mat>, Mat>::value, "Mat must be sparse");
igl::slice(A,I,J,B);
}
};
template <typename Mat> struct arap_dof_slice_helper<Mat,false>
{
static void slice(const Mat & A, const Eigen::VectorXi & I, const Eigen::VectorXi & J, Mat & B)
{
B = A(I,J);
}
};
#endif
// A careful derivation of this implementation is given in the corresponding
// matlab function arap_dof.m
template <typename LbsMatrixType, typename SSCALAR>
@@ -99,9 +121,7 @@ IGL_INLINE bool igl::arap_dof_precomputation(
MatrixXi GF(F.rows(),F.cols());
for(int j = 0;j<F.cols();j++)
{
Matrix<int,Eigen::Dynamic,1> GFj;
slice(G,F.col(j),GFj);
GF.col(j) = GFj;
GF.col(j) = G(F.col(j));
}
mode<int>(GF,2,GG);
}else
@@ -183,7 +203,20 @@ IGL_INLINE bool igl::arap_dof_precomputation(
//printf("CSM_M(): Mi\n");
LbsMatrixType M_i;
//printf("CSM_M(): slice\n");
slice(M,(span_n.array()+i*n).matrix().eval(),span_mlbs_cols,M_i);
#if __cplusplus >= 201703L
// Check if LbsMatrixType is a sparse matrix
if constexpr (std::is_base_of<SparseMatrixBase<LbsMatrixType>, LbsMatrixType>::value)
{
slice(M,(span_n.array()+i*n).matrix().eval(),span_mlbs_cols,M_i);
}
else
{
M_i = M((span_n.array()+i*n).eval(),span_mlbs_cols);
}
#else
constexpr bool LbsMatrixTypeIsSparse = std::is_base_of<SparseMatrixBase<LbsMatrixType>, LbsMatrixType>::value;
arap_dof_slice_helper<LbsMatrixType,LbsMatrixTypeIsSparse>::slice(M,(span_n.array()+i*n).matrix().eval(),span_mlbs_cols,M_i);
#endif
LbsMatrixType M_i_dim;
data.CSM_M[i].resize(k*data.dim,data.m*data.dim*(data.dim+1));
assert(data.CSM_M[i].cols() == M.cols());
@@ -543,17 +576,17 @@ IGL_INLINE bool igl::arap_dof_recomputation(
#endif
// Compute dense solve matrix (alternative of matrix factorization)
//printf("min_quad_dense_precompute()\n");
//printf("kkt_inverse()\n");
MatrixXd Qfull(*Q);
MatrixXd A_eqfull(A_eq);
MatrixXd M_Solve;
double timer0_start = get_seconds_hires();
double timer0_start = get_seconds();
bool use_lu = data.effective_dim != 2;
//use_lu = false;
//printf("use_lu: %s\n",(use_lu?"TRUE":"FALSE"));
min_quad_dense_precompute(Qfull, A_eqfull, use_lu,M_Solve);
double timer0_end = get_seconds_hires();
kkt_inverse(Qfull, A_eqfull, use_lu,M_Solve);
double timer0_end = get_seconds();
verbose("Bob timing: %.20f\n", (timer0_end - timer0_start)*1000.0);
// Precompute full solve matrix:
@@ -616,14 +649,14 @@ IGL_INLINE bool igl::arap_dof_update(
using namespace Eigen;
typedef Matrix<SSCALAR, Dynamic, Dynamic> MatrixXS;
#ifdef ARAP_GLOBAL_TIMING
double timer_start = get_seconds_hires();
double timer_start = get_seconds();
#endif
// number of dimensions
assert((int)data.CSM_M.size() == data.dim);
assert((int)L0.size() == (data.m)*data.dim*(data.dim+1));
assert(max_iters >= 0);
assert(tol >= 0);
IGL_ASSERT((int)data.CSM_M.size() == data.dim);
IGL_ASSERT((int)L0.size() == (data.m)*data.dim*(data.dim+1));
IGL_ASSERT(max_iters >= 0);
IGL_ASSERT(tol >= 0);
// timing variables
double
@@ -668,9 +701,8 @@ IGL_INLINE bool igl::arap_dof_update(
MatrixXS R(data.dim,data.dim*k);
Eigen::Matrix<SSCALAR,Eigen::Dynamic,1> Rcol(data.dim * data.dim * k);
Matrix<SSCALAR,Dynamic,1> B_eq_SSCALAR = B_eq.cast<SSCALAR>();
Matrix<SSCALAR,Dynamic,1> B_eq_fix_SSCALAR;
Matrix<SSCALAR,Dynamic,1> L0SSCALAR = L0.cast<SSCALAR>();
slice(L0SSCALAR, data.fixed_dim, B_eq_fix_SSCALAR);
Matrix<SSCALAR,Dynamic,1> B_eq_fix_SSCALAR = L0SSCALAR(data.fixed_dim);
//MatrixXS rhsFull(Rcol.rows() + B_eq.rows() + B_eq_fix_SSCALAR.rows(), 1);
MatrixXS Lsep(data.m*(data.dim + 1), 3);
@@ -686,7 +718,7 @@ IGL_INLINE bool igl::arap_dof_update(
MatrixXS L_part1(data.dim * (data.dim + 1) * data.m, 1);
#ifdef ARAP_GLOBAL_TIMING
double timer_prepFinished = get_seconds_hires();
double timer_prepFinished = get_seconds();
#endif
#ifdef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
@@ -697,7 +729,7 @@ IGL_INLINE bool igl::arap_dof_update(
{
if(data.print_timings)
{
sec_start = get_seconds_hires();
sec_start = get_seconds();
}
#ifndef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
@@ -722,7 +754,7 @@ IGL_INLINE bool igl::arap_dof_update(
if(data.print_timings)
{
sec_covGather = get_seconds_hires();
sec_covGather = get_seconds();
}
#ifdef EXTREME_VERBOSE
@@ -747,7 +779,7 @@ IGL_INLINE bool igl::arap_dof_update(
if(data.print_timings)
{
sec_fitRotations = get_seconds_hires();
sec_fitRotations = get_seconds();
}
///////////////////////////////////////////////////////////////////////////
@@ -766,7 +798,7 @@ IGL_INLINE bool igl::arap_dof_update(
if(data.print_timings)
{
sec_prepMult = get_seconds_hires();
sec_prepMult = get_seconds();
}
L_part1xyz = data.CSolveBlock1 * Rxyz;
@@ -824,7 +856,7 @@ IGL_INLINE bool igl::arap_dof_update(
if(data.print_timings)
{
sec_solve = get_seconds_hires();
sec_solve = get_seconds();
}
#ifndef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
@@ -835,7 +867,7 @@ IGL_INLINE bool igl::arap_dof_update(
if(data.print_timings)
{
sec_end = get_seconds_hires();
sec_end = get_seconds();
#ifndef WIN32
// trick to get sec_* variables to compile without warning on mac
if(false)
@@ -861,7 +893,7 @@ IGL_INLINE bool igl::arap_dof_update(
assert(L.cols() == 1);
#ifdef ARAP_GLOBAL_TIMING
double timer_finito = get_seconds_hires();
double timer_finito = get_seconds();
printf(
"ARAP preparation = %f, "
"all %i iterations = %f [ms]\n",

View File

@@ -14,75 +14,76 @@
#include "ARAPEnergyType.h"
#include <vector>
/// @file arap_dof.h
/// @brief "Fast Automatic Skinning Transformations" [Jacobson et al.\ 2012]
///
/// Arap DOF precomputation consists of two parts the computation. The first is
/// that which depends solely on the mesh (V,F), the linear blend skinning
/// weights (M) and the groups G. Then there's the part that depends on the
/// previous precomputation and the list of free and fixed vertices.
///
///
/// #### Caller example:
///
/// Once:
/// arap_dof_precomputation(...)
///
/// Each frame:
/// while(not satisfied)
/// arap_dof_update(...)
/// end
/// The code and variables differ from the description in Section 3 of "Fast
/// Automatic Skinning Transformations" by [Jacobson et al. 2012]
///
/// Here is a useful conversion table:
///
/// [article] [code]
/// S = \tilde{K} T S = CSM * Lsep
/// S --> R S --> R --shuffled--> Rxyz
/// Gamma_solve RT = Pi_1 \tilde{K} RT L_part1xyz = CSolveBlock1 * Rxyz
/// Pi_1 \tilde{K} CSolveBlock1
/// Peq = [T_full; P_pos]
/// T_full B_eq_fix <--- L0
/// P_pos B_eq
/// Pi_2 * P_eq = Lpart2and3 = Lpart2 + Lpart3
/// Pi_2_left T_full + Lpart3 = M_fullsolve(right) * B_eq_fix
/// Pi_2_right P_pos Lpart2 = M_fullsolve(left) * B_eq
/// T = [Pi_1 Pi_2] [\tilde{K}TRT P_eq] L = Lpart1 + Lpart2and3
///
namespace igl
{
// Caller example:
//
// Once:
// arap_dof_precomputation(...)
//
// Each frame:
// while(not satisfied)
// arap_dof_update(...)
// end
template <typename LbsMatrixType, typename SSCALAR>
struct ArapDOFData;
///////////////////////////////////////////////////////////////////////////
//
// Arap DOF precomputation consists of two parts the computation. The first is
// that which depends solely on the mesh (V,F), the linear blend skinning
// weights (M) and the groups G. Then there's the part that depends on the
// previous precomputation and the list of free and fixed vertices.
//
///////////////////////////////////////////////////////////////////////////
// The code and variables differ from the description in Section 3 of "Fast
// Automatic Skinning Transformations" by [Jacobson et al. 2012]
//
// Here is a useful conversion table:
//
// [article] [code]
// S = \tilde{K} T S = CSM * Lsep
// S --> R S --> R --shuffled--> Rxyz
// Gamma_solve RT = Pi_1 \tilde{K} RT L_part1xyz = CSolveBlock1 * Rxyz
// Pi_1 \tilde{K} CSolveBlock1
// Peq = [T_full; P_pos]
// T_full B_eq_fix <--- L0
// P_pos B_eq
// Pi_2 * P_eq = Lpart2and3 = Lpart2 + Lpart3
// Pi_2_left T_full + Lpart3 = M_fullsolve(right) * B_eq_fix
// Pi_2_right P_pos Lpart2 = M_fullsolve(left) * B_eq
// T = [Pi_1 Pi_2] [\tilde{K}TRT P_eq] L = Lpart1 + Lpart2and3
//
// Precomputes the system we are going to optimize. This consists of building
// constructor matrices (to compute covariance matrices from transformations
// and to build the poisson solve right hand side from rotation matrix entries)
// and also prefactoring the poisson system.
//
// Inputs:
// V #V by dim list of vertex positions
// F #F by {3|4} list of face indices
// M #V * dim by #handles * dim * (dim+1) matrix such that
// new_V(:) = LBS(V,W,A) = reshape(M * A,size(V)), where A is a column
// vectors formed by the entries in each handle's dim by dim+1
// transformation matrix. Specifcally, A =
// reshape(permute(Astack,[3 1 2]),n*dim*(dim+1),1)
// or A = [Lxx;Lyx;Lxy;Lyy;tx;ty], and likewise for other dim
// if Astack(:,:,i) is the dim by (dim+1) transformation at handle i
// handles are ordered according to P then BE (point handles before bone
// handles)
// G #V list of group indices (1 to k) for each vertex, such that vertex i
// is assigned to group G(i)
// Outputs:
// data structure containing all necessary precomputation for calling
// arap_dof_update
// Returns true on success, false on error
//
// See also: lbs_matrix_column
/// Precomputes the system to optimize for "Fast Automatic Skinning
/// Transformations" [Jacobson et al.\ 2012] skinning degrees of freedom
/// optimization using as-rigid-as-possible energy. This consists of building
/// constructor matrices (to compute covariance matrices from transformations
/// and to build the poisson solve right hand side from rotation matrix entries)
/// and also prefactoring the poisson system.
///
/// @param[in] V #V by dim list of vertex positions
/// @param[in] F #F by {3|4} list of face indices
/// @param[in] M #V * dim by #handles * dim * (dim+1) matrix such that
/// new_V(:) = LBS(V,W,A) = reshape(M * A,size(V)), where A is a column
/// vectors formed by the entries in each handle's dim by dim+1
/// transformation matrix. Specifcally, A =
/// reshape(permute(Astack,[3 1 2]),n*dim*(dim+1),1)
/// or A = [Lxx;Lyx;Lxy;Lyy;tx;ty], and likewise for other dim
/// if Astack(:,:,i) is the dim by (dim+1) transformation at handle i
/// handles are ordered according to P then BE (point handles before bone
/// handles)
/// @param[in] G #V list of group indices (1 to k) for each vertex, such that vertex i
/// is assigned to group G(i)
/// @param[out] data structure containing all necessary precomputation for calling
/// arap_dof_update
/// @return true on success, false on error
///
/// \see lbs_matrix_column
///
/// \fileinfo
template <typename LbsMatrixType, typename SSCALAR>
IGL_INLINE bool arap_dof_precomputation(
const Eigen::MatrixXd & V,
@@ -91,49 +92,49 @@ namespace igl
const Eigen::Matrix<int,Eigen::Dynamic,1> & G,
ArapDOFData<LbsMatrixType, SSCALAR> & data);
// Should always be called after arap_dof_precomputation, but may be called in
// between successive calls to arap_dof_update, recomputes precomputation
// given that there are only changes in free and fixed
//
// Inputs:
// fixed_dim list of transformation element indices for fixed (or partailly
// fixed) handles: not necessarily the complement of 'free'
// NOTE: the constraints for fixed transformations still need to be
// present in A_eq
// A_eq dim*#constraint_points by m*dim*(dim+1) matrix of linear equality
// constraint coefficients. Each row corresponds to a linear constraint,
// so that A_eq * L = Beq says that the linear transformation entries in
// the column L should produce the user supplied positional constraints
// for each handle in Beq. The row A_eq(i*dim+d) corresponds to the
// constrain on coordinate d of position i
// Outputs:
// data structure containing all necessary precomputation for calling
// arap_dof_update
// Returns true on success, false on error
//
// See also: lbs_matrix_column
/// Should always be called after arap_dof_precomputation, but may be called in
/// between successive calls to arap_dof_update, recomputes precomputation
/// given that there are only changes in free and fixed
///
/// @param[in] fixed_dim list of transformation element indices for fixed (or partailly
/// fixed) handles: not necessarily the complement of 'free'
/// NOTE: the constraints for fixed transformations still need to be
/// present in A_eq
/// @param[in] A_eq dim*#constraint_points by m*dim*(dim+1) matrix of linear equality
/// constraint coefficients. Each row corresponds to a linear constraint,
/// so that A_eq * L = Beq says that the linear transformation entries in
/// the column L should produce the user supplied positional constraints
/// for each handle in Beq. The row A_eq(i*dim+d) corresponds to the
/// constrain on coordinate d of position i
/// @param[out] data structure containing all necessary precomputation for calling
/// arap_dof_update
/// @return true on success, false on error
///
/// \see lbs_matrix_column
///
/// \fileinfo
template <typename LbsMatrixType, typename SSCALAR>
IGL_INLINE bool arap_dof_recomputation(
const Eigen::Matrix<int,Eigen::Dynamic,1> & fixed_dim,
const Eigen::SparseMatrix<double> & A_eq,
ArapDOFData<LbsMatrixType, SSCALAR> & data);
// Optimizes the transformations attached to each weight function based on
// precomputed system.
//
// Inputs:
// data precomputation data struct output from arap_dof_precomputation
// Beq dim*#constraint_points constraint values.
// L0 #handles * dim * dim+1 list of initial guess transformation entries,
// also holds fixed transformation entries for fixed handles
// max_iters maximum number of iterations
// tol stopping criteria parameter. If variables (linear transformation
// matrix entries) change by less than 'tol' the optimization terminates,
// 0.75 (weak tolerance)
// 0.0 (extreme tolerance)
// Outputs:
// L #handles * dim * dim+1 list of final optimized transformation entries,
// allowed to be the same as L
/// Optimizes the transformations attached to each weight function based on
/// precomputed system.
///
/// @param[in] data precomputation data struct output from arap_dof_precomputation
/// @param[in] Beq dim*#constraint_points constraint values.
/// @param[in] L0 #handles * dim * dim+1 list of initial guess transformation entries,
/// also holds fixed transformation entries for fixed handles
/// @param[in] max_iters maximum number of iterations
/// @param[in] tol stopping criteria parameter. If variables (linear transformation
/// matrix entries) change by less than 'tol' the optimization terminates,
/// 0.75 (weak tolerance)
/// 0.0 (extreme tolerance)
/// @param[out] L #handles * dim * dim+1 list of final optimized transformation entries,
/// allowed to be the same as L
///
/// \fileinfo
template <typename LbsMatrixType, typename SSCALAR>
IGL_INLINE bool arap_dof_update(
const ArapDOFData<LbsMatrixType,SSCALAR> & data,
@@ -144,88 +145,89 @@ namespace igl
Eigen::MatrixXd & L
);
// Structure that contains fields for all precomputed data or data that needs
// to be remembered at update
/// Structure that contains fields for all precomputed data or data that needs
/// to be remembered at update
///
/// \fileinfo
template <typename LbsMatrixType, typename SSCALAR>
struct ArapDOFData
{
/// Matrix with SSCALAR type
typedef Eigen::Matrix<SSCALAR, Eigen::Dynamic, Eigen::Dynamic> MatrixXS;
// Type of arap energy we're solving
/// Type of arap energy we're solving
igl::ARAPEnergyType energy;
//// LU decomposition precomptation data; note: not used by araf_dop_update
//// any more, replaced by M_FullSolve
//igl::min_quad_with_fixed_data<double> lu_data;
// List of indices of fixed transformation entries
/// List of indices of fixed transformation entries
Eigen::Matrix<int,Eigen::Dynamic,1> fixed_dim;
// List of precomputed covariance scatter matrices multiplied by lbs
// matrices
//std::vector<Eigen::SparseMatrix<double> > CSM_M;
/// List of precomputed covariance scatter matrices multiplied by lbs
/// matrices
std::vector<Eigen::MatrixXd> CSM_M;
/// @private
LbsMatrixType M_KG;
// Number of mesh vertices
/// Number of mesh vertices
int n;
// Number of weight functions
/// Number of weight functions
int m;
// Number of dimensions
/// Number of dimensions
int dim;
// Effective dimensions
/// Effective dimensions
int effective_dim;
// List of indices into C of positional constraints
/// List of indices into C of positional constraints
Eigen::Matrix<int,Eigen::Dynamic,1> interpolated;
/// Mask of free variables
std::vector<bool> free_mask;
// Full quadratic coefficients matrix before lagrangian (should be dense)
/// Full quadratic coefficients matrix before lagrangian (should be dense)
LbsMatrixType Q;
//// Solve matrix for the global step
//Eigen::MatrixXd M_Solve; // TODO: remove from here
// Full solve matrix that contains also conversion from rotations to the right hand side,
// i.e., solves Poisson transformations just from rotations and positional constraints
/// Full solve matrix that contains also conversion from rotations to the right hand side,
/// i.e., solves Poisson transformations just from rotations and positional constraints
MatrixXS M_FullSolve;
// Precomputed condensed matrices (3x3 commutators folded to 1x1):
/// Precomputed condensed matrices (3x3 commutators folded to 1x1):
MatrixXS CSM;
/// @private
MatrixXS CSolveBlock1;
// Print timings at each update
/// Print timings at each update
bool print_timings;
// Dynamics
/// dynamics
bool with_dynamics;
// I'm hiding the extra dynamics stuff in this struct, which sort of defeats
// the purpose of this function-based coding style...
// Time step
/// Time step
double h;
// L0 #handles * dim * dim+1 list of transformation entries from
// previous solve
/// #handles * dim * dim+1 list of transformation entries from
/// previous solve
MatrixXS L0;
//// Lm1 #handles * dim * dim+1 list of transformation entries from
//// previous-previous solve
//MatrixXS Lm1;
// "Velocity"
/// "Velocity"
MatrixXS Lvel0;
// #V by dim matrix of external forces
// fext
/// #V by dim matrix of external forces
MatrixXS fext;
// Mass_tilde: MT * Mass * M
/// Mass_tilde: MT * Mass * M
LbsMatrixType Mass_tilde;
// Force due to gravity (premultiplier)
/// Force due to gravity (premultiplier)
Eigen::MatrixXd fgrav;
// Direction of gravity
/// Direction of gravity
Eigen::Vector3d grav_dir;
// Magnitude of gravity
/// Magnitude of gravity
double grav_mag;
// Π1 from the paper
/// Π1 from the paper
MatrixXS Pi_1;
// Default values
// @private Default values
ArapDOFData():
energy(igl::ARAP_ENERGY_TYPE_SPOKES),
with_dynamics(false),

View File

@@ -10,13 +10,13 @@
#include "cotmatrix_entries.h"
#include <Eigen/Dense>
template <typename MatV, typename MatF, typename Scalar>
template <typename MatV, typename MatF, typename MatK>
IGL_INLINE void igl::arap_linear_block(
const MatV & V,
const MatF & F,
const int d,
const igl::ARAPEnergyType energy,
Eigen::SparseMatrix<Scalar> & Kd)
MatK & Kd)
{
switch(energy)
{
@@ -36,13 +36,15 @@ IGL_INLINE void igl::arap_linear_block(
}
template <typename MatV, typename MatF, typename Scalar>
template <typename MatV, typename MatF, typename MatK>
IGL_INLINE void igl::arap_linear_block_spokes(
const MatV & V,
const MatF & F,
const int d,
Eigen::SparseMatrix<Scalar> & Kd)
MatK & Kd)
{
typedef typename MatK::Scalar Scalar;
using namespace std;
using namespace Eigen;
// simplex size (3: triangles, 4: tetrahedra)
@@ -101,13 +103,15 @@ IGL_INLINE void igl::arap_linear_block_spokes(
Kd.makeCompressed();
}
template <typename MatV, typename MatF, typename Scalar>
template <typename MatV, typename MatF, typename MatK>
IGL_INLINE void igl::arap_linear_block_spokes_and_rims(
const MatV & V,
const MatF & F,
const int d,
Eigen::SparseMatrix<Scalar> & Kd)
MatK & Kd)
{
typedef typename MatK::Scalar Scalar;
using namespace std;
using namespace Eigen;
// simplex size (3: triangles, 4: tetrahedra)
@@ -183,13 +187,14 @@ IGL_INLINE void igl::arap_linear_block_spokes_and_rims(
Kd.makeCompressed();
}
template <typename MatV, typename MatF, typename Scalar>
template <typename MatV, typename MatF, typename MatK>
IGL_INLINE void igl::arap_linear_block_elements(
const MatV & V,
const MatF & F,
const int d,
Eigen::SparseMatrix<Scalar> & Kd)
MatK & Kd)
{
typedef typename MatK::Scalar Scalar;
using namespace std;
using namespace Eigen;
// simplex size (3: triangles, 4: tetrahedra)
@@ -249,5 +254,6 @@ IGL_INLINE void igl::arap_linear_block_elements(
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template IGL_INLINE void igl::arap_linear_block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, int, igl::ARAPEnergyType, Eigen::SparseMatrix<double, 0, int>&);
template void igl::arap_linear_block<Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >, Eigen::SparseMatrix<double, 0, int> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, igl::ARAPEnergyType, Eigen::SparseMatrix<double, 0, int>&);
template void igl::arap_linear_block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::SparseMatrix<double, 0, int> >(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, int, igl::ARAPEnergyType, Eigen::SparseMatrix<double, 0, int>&);
#endif

View File

@@ -10,65 +10,100 @@
#include "igl_inline.h"
#include <Eigen/Sparse>
#include <igl/ARAPEnergyType.h>
#include "ARAPEnergyType.h"
namespace igl
{
// ARAP_LINEAR_BLOCK constructs a block of the matrix which constructs the
// linear terms of a given arap energy. When treating rotations as knowns
// (arranged in a column) then this constructs Kd of K such that the linear
// portion of the energy is as a column:
// K * R = [Kx Z ... Ky Z ...
// Z Kx ... Z Ky ...
// ... ]
// These blocks are also used to build the "covariance scatter matrices".
// Here we want to build a scatter matrix that multiplies against positions
// (treated as known) producing covariance matrices to fit each rotation.
// Notice that in the case of the RHS of the poisson solve the rotations are
// known and the positions unknown, and vice versa for rotation fitting.
// These linear block just relate the rotations to the positions, linearly in
// each.
//
// Templates:
// MatV vertex position matrix, e.g. Eigen::MatrixXd
// MatF face index matrix, e.g. Eigen::MatrixXd
// Scalar e.g. double
// Inputs:
// V #V by dim list of initial domain positions
// F #F by #simplex size list of triangle indices into V
// d coordinate of linear constructor to build
// energy ARAPEnergyType enum value defining which energy is being used.
// See ARAPEnergyType.h for valid options and explanations.
// Outputs:
// Kd #V by #V/#F block of the linear constructor matrix corresponding to
// coordinate d
//
template <typename MatV, typename MatF, typename Scalar>
/// Constructs a block of the matrix which constructs the
/// linear terms of a given arap energy. When treating rotations as knowns
/// (arranged in a column) then this constructs Kd of K such that the linear
/// portion of the energy is as a column:
///
/// K * R = [Kx Z ... Ky Z ...
/// Z Kx ... Z Ky ...
/// ... ]
///
/// These blocks are also used to build the "covariance scatter matrices".
/// Here we want to build a scatter matrix that multiplies against positions
/// (treated as known) producing covariance matrices to fit each rotation.
/// Notice that in the case of the RHS of the poisson solve the rotations are
/// known and the positions unknown, and vice versa for rotation fitting.
/// These linear block just relate the rotations to the positions, linearly in
/// each.
///
/// @tparam MatV vertex position matrix, e.g. Eigen::MatrixXd
/// @tparam MatF face index matrix, e.g. Eigen::MatrixXd
/// @tparam Scalar e.g. double
/// @param[in] V #V by dim list of initial domain positions
/// @param[in] F #F by #simplex size list of triangle indices into V
/// @param[in] d coordinate of linear constructor to build
/// @param[in] energy ARAPEnergyType enum value defining which energy is being used.
/// See ARAPEnergyType.h for valid options and explanations.
/// @param[out] Kd #V by #V/#F block of the linear constructor matrix
/// corresponding to coordinate d
///
/// \see ARAPEnergyType
template <typename MatV, typename MatF, typename MatK>
IGL_INLINE void arap_linear_block(
const MatV & V,
const MatF & F,
const int d,
const igl::ARAPEnergyType energy,
Eigen::SparseMatrix<Scalar> & Kd);
// Helper functions for each energy type
template <typename MatV, typename MatF, typename Scalar>
MatK & Kd);
/// Constructs a block of the matrix which constructs the linear terms for
/// spokes energy.
///
/// @tparam MatV vertex position matrix, e.g. Eigen::MatrixXd
/// @tparam MatF face index matrix, e.g. Eigen::MatrixXd
/// @tparam Scalar e.g. double
/// @param[in] V #V by dim list of initial domain positions
/// @param[in] F #F by #simplex size list of triangle indices into V
/// @param[in] d coordinate of linear constructor to build (0 index)
/// See ARAPEnergyType.h for valid options and explanations.
/// @param[out] Kd #V by #V block of the linear constructor matrix
/// corresponding to coordinate d
template <typename MatV, typename MatF, typename MatK>
IGL_INLINE void arap_linear_block_spokes(
const MatV & V,
const MatF & F,
const int d,
Eigen::SparseMatrix<Scalar> & Kd);
template <typename MatV, typename MatF, typename Scalar>
MatK & Kd);
/// Constructs a block of the matrix which constructs the linear terms for
/// spokes and rims energy.
///
/// @tparam MatV vertex position matrix, e.g. Eigen::MatrixXd
/// @tparam MatF face index matrix, e.g. Eigen::MatrixXd
/// @tparam Scalar e.g. double
/// @param[in] V #V by dim list of initial domain positions
/// @param[in] F #F by #simplex size list of triangle indices into V
/// @param[in] d coordinate of linear constructor to build (0 index)
/// See ARAPEnergyType.h for valid options and explanations.
/// @param[out] Kd #V by #V block of the linear constructor matrix
/// corresponding to coordinate d
template <typename MatV, typename MatF, typename MatK>
IGL_INLINE void arap_linear_block_spokes_and_rims(
const MatV & V,
const MatF & F,
const int d,
Eigen::SparseMatrix<Scalar> & Kd);
template <typename MatV, typename MatF, typename Scalar>
MatK & Kd);
/// Constructs a block of the matrix which constructs the linear terms for
/// per element energy.
///
/// @tparam MatV vertex position matrix, e.g. Eigen::MatrixXd
/// @tparam MatF face index matrix, e.g. Eigen::MatrixXd
/// @tparam Scalar e.g. double
/// @param[in] V #V by dim list of initial domain positions
/// @param[in] F #F by #simplex size list of triangle indices into V
/// @param[in] d coordinate of linear constructor to build (0 index)
/// See ARAPEnergyType.h for valid options and explanations.
/// @param[out] Kd #V by #F block of the linear constructor matrix
/// corresponding to coordinate d
template <typename MatV, typename MatF, typename MatK>
IGL_INLINE void arap_linear_block_elements(
const MatV & V,
const MatF & F,
const int d,
Eigen::SparseMatrix<Scalar> & Kd);
MatK & Kd);
}
#ifndef IGL_STATIC_LIBRARY

View File

@@ -1,9 +1,9 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "arap_rhs.h"
#include "arap_linear_block.h"
@@ -12,12 +12,13 @@
#include "cat.h"
#include <iostream>
template<typename DerivedV, typename DerivedF, typename DerivedK>
IGL_INLINE void igl::arap_rhs(
const Eigen::MatrixXd & V,
const Eigen::MatrixXi & F,
const int dim,
const igl::ARAPEnergyType energy,
Eigen::SparseMatrix<double>& K)
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F,
const int dim,
const igl::ARAPEnergyType energy,
Eigen::SparseCompressedBase<DerivedK>& K)
{
using namespace std;
using namespace Eigen;
@@ -48,7 +49,7 @@ IGL_INLINE void igl::arap_rhs(
return;
}
SparseMatrix<double> KX,KY,KZ;
Eigen::SparseMatrix<typename DerivedK::Scalar> KX,KY,KZ;
arap_linear_block(V,F,0,energy,KX);
arap_linear_block(V,F,1,energy,KY);
if(Vdim == 2)
@@ -62,7 +63,7 @@ IGL_INLINE void igl::arap_rhs(
K = cat(2,cat(2,repdiag(KX,dim),repdiag(KY,dim)),repdiag(KZ,dim));
}else if(dim ==2)
{
SparseMatrix<double> ZZ(KX.rows()*2,KX.cols());
Eigen::SparseMatrix<typename DerivedK::Scalar> ZZ(KX.rows()*2,KX.cols());
K = cat(2,cat(2,
cat(2,repdiag(KX,dim),ZZ),
cat(2,repdiag(KY,dim),ZZ)),
@@ -84,6 +85,11 @@ IGL_INLINE void igl::arap_rhs(
Vdim);
return;
}
}
#ifdef IGL_STATIC_LIBRARY
template void igl::arap_rhs(const Eigen::MatrixBase<Eigen::MatrixXd> & V, const Eigen::MatrixBase<Eigen::MatrixXi> & F,const int dim, const igl::ARAPEnergyType energy,Eigen::SparseCompressedBase<Eigen::SparseMatrix<double>>& K);
#endif

View File

@@ -1,40 +1,40 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.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_ARAP_RHS_H
#define IGL_ARAP_RHS_H
#include "igl_inline.h"
#include "ARAPEnergyType.h"
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <igl/ARAPEnergyType.h>
namespace igl
{
// ARAP_RHS build right-hand side constructor of global poisson solve for
// various Arap energies
// Inputs:
// V #V by Vdim list of initial domain positions
// F #F by 3 list of triangle indices into V
// dim dimension being used at solve time. For deformation usually dim =
// V.cols(), for surface parameterization V.cols() = 3 and dim = 2
// energy igl::ARAPEnergyType enum value defining which energy is being
// used. See igl::ARAPEnergyType.h for valid options and explanations.
// Outputs:
// K #V*dim by #(F|V)*dim*dim matrix such that:
// b = K * reshape(permute(R,[3 1 2]),size(V|F,1)*size(V,2)*size(V,2),1);
//
// See also: arap_linear_block
/// Right-hand side constructor of global poisson solve for various Arap
/// energies
///
/// @param[in] V #V by Vdim list of initial domain positions
/// @param[in] F #F by 3 list of triangle indices into V
/// @param[in] dim dimension being used at solve time. For deformation usually dim =
/// V.cols(), for surface parameterization V.cols() = 3 and dim = 2
/// @param[in] energy igl::ARAPEnergyType enum value defining which energy is being
/// used. See igl::ARAPEnergyType.h for valid options and explanations.
/// @param[out] K #V*dim by #(F|V)*dim*dim matrix such that:
/// b = K * reshape(permute(R,[3 1 2]),size(V|F,1)*size(V,2)*size(V,2),1);
///
/// \see arap_linear_block
template<typename DerivedV, typename DerivedF, typename DerivedK>
IGL_INLINE void arap_rhs(
const Eigen::MatrixXd & V,
const Eigen::MatrixXi & F,
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F,
const int dim,
const igl::ARAPEnergyType energy,
Eigen::SparseMatrix<double>& K);
Eigen::SparseCompressedBase<DerivedK>& K);
}
#ifndef IGL_STATIC_LIBRARY
#include "arap_rhs.cpp"

View File

@@ -0,0 +1,69 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "average_from_edges_onto_vertices.h"
template<typename DerivedF,typename DerivedE,typename DerivedoE,
typename DeriveduE,typename DeriveduV>
IGL_INLINE void
igl::average_from_edges_onto_vertices(
const Eigen::MatrixBase<DerivedF> &F,
const Eigen::MatrixBase<DerivedE> &E,
const Eigen::MatrixBase<DerivedoE> &oE,
const Eigen::MatrixBase<DeriveduE> &uE,
Eigen::PlainObjectBase<DeriveduV> &uV)
{
using Scalar = typename DeriveduE::Scalar;
using VecX = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
using Int = typename DerivedF::Scalar;
assert(E.rows()==F.rows() && "E does not match dimensions of F.");
assert(oE.rows()==F.rows() && "oE does not match dimensions of F.");
assert(E.cols()==3 && F.cols()==3 && oE.cols()==3 &&
"This method is for triangle meshes.");
const Int n = F.maxCoeff()+1;
VecX edgesPerVertex(n);
edgesPerVertex.setZero();
uV.resize(n,1);
uV.setZero();
for(Eigen::Index i=0; i<F.rows(); ++i) {
for(int j=0; j<3; ++j) {
if(oE(i,j)<0) {
continue;
}
const Int e = E(i,j);
const Int vi=F(i,(j+1)%3), vj=F(i,(j+2)%3);
//Count vertex valence
++edgesPerVertex(vi);
++edgesPerVertex(vj);
//Average uE value onto vertices
uV(vi) += uE(e);
uV(vj) += uE(e);
}
}
//Divide by valence
for(Int i=0; i<n; ++i) {
const Scalar valence = edgesPerVertex(i);
if(valence>0) {
uV(i) /= valence;
}
}
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::average_from_edges_onto_vertices<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template void igl::average_from_edges_onto_vertices<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template void igl::average_from_edges_onto_vertices<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
#endif

View File

@@ -0,0 +1,38 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_AVERAGE_FROM_EDGES_ONTO_VERTICES_H
#define IGL_AVERAGE_FROM_EDGES_ONTO_VERTICES_H
#include "igl_inline.h"
#include <Eigen/Dense>
namespace igl
{
/// Move a scalar field defined on edges to vertices by averaging
///
/// @param[in] F #F by 3 triangle mesh connectivity
/// @param[in] E #F by 3 mapping from each halfedge to each edge
/// @param[in] oE #F by 3 orientation as generated by orient_halfedges
/// @param[in] uE #uE by 1 list of scalars
/// @param[out] uV #V by 1 list of scalar defined on vertices
///
/// \see orient_halfedges
template<typename DerivedF,typename DerivedE,typename DerivedoE,
typename DeriveduE,typename DeriveduV>
IGL_INLINE void average_from_edges_onto_vertices(
const Eigen::MatrixBase<DerivedF> &F,
const Eigen::MatrixBase<DerivedE> &E,
const Eigen::MatrixBase<DerivedoE> &oE,
const Eigen::MatrixBase<DeriveduE> &uE,
Eigen::PlainObjectBase<DeriveduV> &uV);
}
#ifndef IGL_STATIC_LIBRARY
# include "average_from_edges_onto_vertices.cpp"
#endif
#endif

View File

@@ -7,23 +7,21 @@
// obtain one at http://mozilla.org/MPL/2.0/.
#include "average_onto_faces.h"
template <typename T, typename I>
IGL_INLINE void igl::average_onto_faces(const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &V,
const Eigen::Matrix<I, Eigen::Dynamic, Eigen::Dynamic> &F,
const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &S,
Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &SF)
template <typename DerivedF, typename DerivedS, typename DerivedSF>
IGL_INLINE void igl::average_onto_faces(
const Eigen::MatrixBase<DerivedF> & F,
const Eigen::MatrixBase<DerivedS> & S,
Eigen::PlainObjectBase<DerivedSF> & SF)
{
SF = Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>::Zero(F.rows(),S.cols());
SF.setConstant(F.rows(),S.cols(),0);
for (int i = 0; i <F.rows(); ++i)
for (int j = 0; j<F.cols(); ++j)
SF.row(i) += S.row(F(i,j));
SF.array() /= F.cols();
};
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::average_onto_faces<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
#endif

View File

@@ -12,21 +12,16 @@
#include <Eigen/Dense>
namespace igl
{
// average_onto_vertices
// Move a scalar field defined on faces to vertices by averaging
//
// Input:
// V,F: mesh
// S: scalar field defined on vertices, Vx1
//
// Output:
// SV: scalar field defined on faces
template <typename T, typename I>
/// Move a scalar field defined on vertices to faces by averaging
///
/// @param[in] F #F by ss list of simples/faces
/// @param[in] S #V by dim list of per-vertex values
/// @param[out] SF #F by dim list of per-face values
template <typename DerivedF, typename DerivedS, typename DerivedSF>
IGL_INLINE void average_onto_faces(
const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &V,
const Eigen::Matrix<I, Eigen::Dynamic, Eigen::Dynamic> &F,
const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &S,
Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &SF);
const Eigen::MatrixBase<DerivedF> & F,
const Eigen::MatrixBase<DerivedS> & S,
Eigen::PlainObjectBase<DerivedSF> & SF);
}
#ifndef IGL_STATIC_LIBRARY

View File

@@ -7,11 +7,11 @@
// obtain one at http://mozilla.org/MPL/2.0/.
#include "average_onto_vertices.h"
template<typename DerivedV,typename DerivedF,typename DerivedS>
template<typename DerivedV,typename DerivedF,typename DerivedS,typename DerivedSV >
IGL_INLINE void igl::average_onto_vertices(const Eigen::MatrixBase<DerivedV> &V,
const Eigen::MatrixBase<DerivedF> &F,
const Eigen::MatrixBase<DerivedS> &S,
Eigen::MatrixBase<DerivedS> &SV)
Eigen::PlainObjectBase<DerivedSV> &SV)
{
SV = DerivedS::Zero(V.rows(),S.cols());
Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,1> COUNT(V.rows());

View File

@@ -1,31 +1,28 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.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_AVERAGE_ONTO_VERTICES_H
#define IGL_AVERAGE_ONTO_VERTICES_H
#include "igl_inline.h"
#include <Eigen/Dense>
namespace igl
namespace igl
{
// average_onto_vertices
// Move a scalar field defined on faces to vertices by averaging
//
// Input:
// V,F: mesh
// S: scalar field defined on faces, Fx1
//
// Output:
// SV: scalar field defined on vertices
template<typename DerivedV,typename DerivedF,typename DerivedS>
/// Move a scalar field defined on faces to vertices by averaging
///
/// @param[in] V #V by 3 list of mesh vertex positions
/// @param[in] F #F by 3 list of mesh face indices into rows of V
/// @param[in] S #F by 1 scalar field defined on faces
/// @param[out] SV #V by 1 scalar field defined on vertices
template<typename DerivedV,typename DerivedF,typename DerivedS,typename DerivedSV>
IGL_INLINE void average_onto_vertices(const Eigen::MatrixBase<DerivedV> &V,
const Eigen::MatrixBase<DerivedF> &F,
const Eigen::MatrixBase<DerivedS> &S,
Eigen::MatrixBase<DerivedS> &SV);
Eigen::PlainObjectBase<DerivedSV> &SV);
}
#ifndef IGL_STATIC_LIBRARY

View File

@@ -1,11 +1,12 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "avg_edge_length.h"
#include "edges.h"
#include <vector>
@@ -14,20 +15,19 @@ IGL_INLINE double igl::avg_edge_length(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F)
{
double avg = 0;
long int count = 0;
typedef typename DerivedF::Scalar Index;
Eigen::Matrix<Index, Eigen::Dynamic, 2> E;
// Augh. Technically this is double counting interior edges...
for (unsigned i=0;i<F.rows();++i)
igl::edges(F, E);
double avg = 0;
for (unsigned i=0;i<E.rows();++i)
{
for (unsigned j=0;j<F.cols();++j)
{
++count;
avg += (V.row(F(i,j)) - V.row(F(i,(j+1)%F.cols()))).norm();
}
avg += (V.row(E(i,0)) - V.row(E(i,1))).norm();
}
return avg / (double) count;
return avg / (double) E.rows();
}
#ifdef IGL_STATIC_LIBRARY

View File

@@ -1,9 +1,9 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.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_AVERAGEEDGELENGTH_H
#define IGL_AVERAGEEDGELENGTH_H
@@ -13,20 +13,18 @@
#include <string>
#include <vector>
namespace igl
namespace igl
{
// Compute the average edge length for the given triangle mesh
// Templates:
// DerivedV derived from vertex positions matrix type: i.e. MatrixXd
// DerivedF derived from face indices matrix type: i.e. MatrixXi
// DerivedL derived from edge lengths matrix type: i.e. MatrixXd
// Inputs:
// V eigen matrix #V by 3
// F #F by simplex-size list of mesh faces (must be simplex)
// Outputs:
// l average edge length
//
// See also: adjacency_matrix
/// Compute the average edge length for the given triangle mesh
///
/// @tparam DerivedV derived from vertex positions matrix type: i.e. MatrixXd
/// @tparam DerivedF derived from face indices matrix type: i.e. MatrixXi
/// @tparam DerivedL derived from edge lengths matrix type: i.e. MatrixXd
/// @param[in] V #V by dim list of mesh vertex positions
/// @param[in] F #F by simplex-size list of mesh faces (must be simplex)
/// @return average edge length
///
/// \see adjacency_matrix
template <typename DerivedV, typename DerivedF>
IGL_INLINE double avg_edge_length(
const Eigen::MatrixBase<DerivedV>& V,

View File

@@ -11,14 +11,15 @@
namespace igl
{
// Convert axis angle representation of a rotation to a quaternion
// A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w),
// such that q = x*i + y*j + z*k + w
// Inputs:
// axis 3d vector
// angle scalar
// Outputs:
// quaternion
/// Convert axis angle representation of a rotation to a quaternion.
/// A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w),
///
/// such that q = x*i + y*j + z*k + w
/// @param[in] axis 3d vector
/// @param[in] angle scalar
/// @param[out] out pointer to new quaternion
///
/// \deprecated Use `Eigen::AngleAxisd` instead
template <typename Q_type>
IGL_INLINE void axis_angle_to_quat(
const Q_type *axis,

View File

@@ -34,18 +34,20 @@ IGL_INLINE void igl::barycenter(
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
template void igl::barycenter<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 4, 0, -1, 4> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> >&);
template void igl::barycenter<Eigen::Matrix<double, -1, 4, 0, -1, 4>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 4, 0, -1, 4> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> >&);
@@ -54,4 +56,9 @@ template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::M
template void igl::barycenter<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
template void igl::barycenter<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 2, 3, 0, 2, 3>, Eigen::Matrix<double, 2, 3, 0, 2, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 2, 3, 0, 2, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 3, 0, 2, 3> >&);
template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 2, 3, 0, 2, 3>, Eigen::Matrix<double, 2, 3, 0, 2, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 2, 3, 0, 2, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 3, 0, 2, 3> >&);
template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
template void igl::barycenter<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>>(Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1>> const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>> const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1>>&);
#endif

View File

@@ -11,14 +11,12 @@
#include <Eigen/Dense>
namespace igl
{
// Computes the barycenter of every simplex
//
// Inputs:
// V #V x dim matrix of vertex coordinates
// F #F x simplex_size matrix of indices of simplex corners into V
// Output:
// BC #F x dim matrix of 3d vertices
//
/// Computes the barycenter of every simplex.
///
/// @param[in] V #V x dim matrix of vertex coordinates
/// @param[in] F #F x simplex_size matrix of indices of simplex corners into V
/// @param[out] BC #F x dim matrix of 3d vertices
///
template <
typename DerivedV,
typename DerivedF,

View File

@@ -11,17 +11,15 @@
#include <Eigen/Core>
namespace igl
{
// Compute barycentric coordinates in a tet
//
// Inputs:
// P #P by 3 Query points in 3d
// A #P by 3 Tet corners in 3d
// B #P by 3 Tet corners in 3d
// C #P by 3 Tet corners in 3d
// D #P by 3 Tet corners in 3d
// Outputs:
// L #P by 4 list of barycentric coordinates
//
/// Compute barycentric coordinates of each point in a corresponding tetrahedron.
///
/// @param[in] P #P by 3 Query points in 3d
/// @param[in] A #P by 3 Tet corners in 3d
/// @param[in] B #P by 3 Tet corners in 3d
/// @param[in] C #P by 3 Tet corners in 3d
/// @param[in] D #P by 3 Tet corners in 3d
/// @param[out] L #P by 4 list of barycentric coordinates
///
template <
typename DerivedP,
typename DerivedA,
@@ -36,16 +34,14 @@ namespace igl
const Eigen::MatrixBase<DerivedC> & C,
const Eigen::MatrixBase<DerivedD> & D,
Eigen::PlainObjectBase<DerivedL> & L);
// Compute barycentric coordinates in a triangle
//
// Inputs:
// P #P by dim Query points
// A #P by dim Triangle corners
// B #P by dim Triangle corners
// C #P by dim Triangle corners
// Outputs:
// L #P by 3 list of barycentric coordinates
//
/// Compute barycentric coordinates in a triangle
///
/// @param[in] P #P by dim Query points
/// @param[in] A #P by dim Triangle corners
/// @param[in] B #P by dim Triangle corners
/// @param[in] C #P by dim Triangle corners
/// @param[out] L #P by 3 list of barycentric coordinates
///
template <
typename DerivedP,
typename DerivedA,

View File

@@ -0,0 +1,42 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "barycentric_interpolation.h"
#include "parallel_for.h"
template <
typename DerivedD,
typename DerivedF,
typename DerivedB,
typename DerivedI,
typename DerivedX>
IGL_INLINE void igl::barycentric_interpolation(
const Eigen::MatrixBase<DerivedD> & D,
const Eigen::MatrixBase<DerivedF> & F,
const Eigen::MatrixBase<DerivedB> & B,
const Eigen::MatrixBase<DerivedI> & I,
Eigen::PlainObjectBase<DerivedX> & X)
{
assert(B.rows() == I.size());
assert(F.cols() == B.cols());
X.setZero(B.rows(),D.cols());
// should use parallel_for
//for(int i = 0;i<X.rows();i++)
parallel_for(X.rows(),[&X,&B,&D,&F,&I](const int i)
{
for(int j = 0;j<F.cols();j++)
{
X.row(i) += B(i,j) * D.row(F(I(i),j));
}
},1000);
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::barycentric_interpolation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
#endif

View File

@@ -0,0 +1,40 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_BARYCENTRIC_INTERPOLATION_H
#define IGL_BARYCENTRIC_INTERPOLATION_H
#include "igl_inline.h"
#include <Eigen/Core>
namespace igl
{
/// Interpolate data on a triangle mesh using barycentric coordinates
///
/// @param[in] D #D by dim list of per-vertex data
/// @param[in] F #F by 3 list of triangle indices
/// @param[in] B #X by 3 list of barycentric corodinates
/// @param[in] I #X list of triangle indices
/// @param[out] X #X by dim list of interpolated data
template <
typename DerivedD,
typename DerivedF,
typename DerivedB,
typename DerivedI,
typename DerivedX>
IGL_INLINE void barycentric_interpolation(
const Eigen::MatrixBase<DerivedD> & D,
const Eigen::MatrixBase<DerivedF> & F,
const Eigen::MatrixBase<DerivedB> & B,
const Eigen::MatrixBase<DerivedI> & I,
Eigen::PlainObjectBase<DerivedX> & X);
}
#ifndef IGL_STATIC_LIBRARY
# include "barycentric_interpolation.cpp"
#endif
#endif

View File

@@ -1,44 +0,0 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "barycentric_to_global.h"
// For error printing
#include <cstdio>
#include <vector>
namespace igl
{
template <typename Scalar, typename Index>
IGL_INLINE Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> barycentric_to_global(
const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & V,
const Eigen::Matrix<Index,Eigen::Dynamic,Eigen::Dynamic> & F,
const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & bc)
{
Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> R;
R.resize(bc.rows(),3);
for (unsigned i=0; i<R.rows(); ++i)
{
unsigned id = round(bc(i,0));
double u = bc(i,1);
double v = bc(i,2);
if (id != -1)
R.row(i) = V.row(F(id,0)) +
((V.row(F(id,1)) - V.row(F(id,0))) * u +
(V.row(F(id,2)) - V.row(F(id,0))) * v );
else
R.row(i) << 0,0,0;
}
return R;
}
}
#ifdef IGL_STATIC_LIBRARY
template Eigen::Matrix<double, -1, -1, 0, -1, -1> igl::barycentric_to_global<double, int>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&);
#endif

View File

@@ -1,42 +0,0 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_BARYCENTRIC2GLOBAL_H
#define IGL_BARYCENTRIC2GLOBAL_H
#include <igl/igl_inline.h>
#include <Eigen/Dense>
#include <Eigen/Sparse>
namespace igl
{
// Converts barycentric coordinates in the embree form to 3D coordinates
// Embree stores barycentric coordinates as triples: fid, bc1, bc2
// fid is the id of a face, bc1 is the displacement of the point wrt the
// first vertex v0 and the edge v1-v0. Similarly, bc2 is the displacement
// wrt v2-v0.
//
// Input:
// V: #Vx3 Vertices of the mesh
// F: #Fxe Faces of the mesh
// bc: #Xx3 Barycentric coordinates, one row per point
//
// Output:
// #X: #Xx3 3D coordinates of all points in bc
template <typename Scalar, typename Index>
IGL_INLINE Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>
barycentric_to_global(
const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & V,
const Eigen::Matrix<Index,Eigen::Dynamic,Eigen::Dynamic> & F,
const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & bc);
}
#ifndef IGL_STATIC_LIBRARY
# include "barycentric_to_global.cpp"
#endif
#endif

View File

@@ -13,12 +13,14 @@
namespace igl
{
// Function like PHP's basename: /etc/sudoers.d --> sudoers.d
// Input:
// path string containing input path
// Returns string containing basename (see php's basename)
//
// See also: dirname, pathinfo
/// Extract basename of file path (like PHP's basename). E.g., /etc/sudoers.d sudoers.d
///
/// @param[in] path string containing input path
/// @return string containing basename (see php's basename)
///
/// \see
/// dirname,
/// pathinfo
IGL_INLINE std::string basename(const std::string & path);
}

View File

@@ -39,10 +39,10 @@ template <
typename Derivedbc,
typename DerivedW>
IGL_INLINE bool igl::bbw(
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedEle> & Ele,
const Eigen::PlainObjectBase<Derivedb> & b,
const Eigen::PlainObjectBase<Derivedbc> & bc,
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedEle> & Ele,
const Eigen::MatrixBase<Derivedb> & b,
const Eigen::MatrixBase<Derivedbc> & bc,
igl::BBWData & data,
Eigen::PlainObjectBase<DerivedW> & W
)
@@ -109,15 +109,20 @@ IGL_INLINE bool igl::bbw(
case SOLVER_STATUS_CONVERGED:
break;
case SOLVER_STATUS_MAX_ITER:
#ifdef IGL_BBW_DEBUG
cerr<<"active_set: max iter without convergence."<<endl;
#endif
break;
case SOLVER_STATUS_ERROR:
default:
#ifdef IGL_BBW_DEBUG
cerr<<"active_set error."<<endl;
#endif
error = true;
}
W.col(i) = Wi;
};
parallel_for(m,optimize_weight,2);
if(error)
{
@@ -138,6 +143,6 @@ IGL_INLINE bool igl::bbw(
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template bool igl::bbw<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, igl::BBWData&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template bool igl::bbw<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>>(Eigen::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<int, -1, 1, 0, -1, 1>> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>> const&, igl::BBWData&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>>&);
#endif

View File

@@ -10,50 +10,49 @@
#include "igl_inline.h"
#include <Eigen/Dense>
#include <igl/active_set.h>
#include "active_set.h"
namespace igl
{
// Container for BBW computation related data and flags
/// Container for BBW computation related data and flags
class BBWData
{
public:
// Enforce partition of unity during optimization (optimize all weight
// simultaneously)
/// Enforce partition of unity during optimization (optimize all weight
/// simultaneously)
bool partition_unity;
// Initial guess
/// Initial guess
Eigen::MatrixXd W0;
/// Parameters for active set solver \see active_set
igl::active_set_params active_set_params;
// Verbosity level
// 0: quiet
// 1: loud
// 2: louder
/// Verbosity level
/// 0: quiet
/// 1: loud
/// 2: louder
int verbosity;
public:
/// @private
IGL_INLINE BBWData();
// Print current state of object
/// Print current state of object
IGL_INLINE void print();
};
// Compute Bounded Biharmonic Weights on a given domain (V,Ele) with a given
// set of boundary conditions
//
// Templates
// DerivedV derived type of eigen matrix for V (e.g. MatrixXd)
// DerivedF derived type of eigen matrix for F (e.g. MatrixXi)
// Derivedb derived type of eigen matrix for b (e.g. VectorXi)
// Derivedbc derived type of eigen matrix for bc (e.g. MatrixXd)
// DerivedW derived type of eigen matrix for W (e.g. MatrixXd)
// Inputs:
// V #V by dim vertex positions
// Ele #Elements by simplex-size list of element indices
// b #b boundary indices into V
// bc #b by #W list of boundary values
// data object containing options, initial guess --> solution and results
// Outputs:
// W #V by #W list of *unnormalized* weights to normalize use
// igl::normalize_row_sums(W,W);
// Returns true on success, false on failure
/// Compute Bounded Biharmonic Weights on a given domain (V,Ele) with a given
/// set of boundary conditions
///
/// @tparam DerivedV derived type of eigen matrix for V (e.g. MatrixXd)
/// @tparam DerivedF derived type of eigen matrix for F (e.g. MatrixXi)
/// @tparam Derivedb derived type of eigen matrix for b (e.g. VectorXi)
/// @tparam Derivedbc derived type of eigen matrix for bc (e.g. MatrixXd)
/// @tparam DerivedW derived type of eigen matrix for W (e.g. MatrixXd)
/// @param[in] V #V by dim vertex positions
/// @param[in] Ele #Elements by simplex-size list of element indices
/// @param[in] b #b boundary indices into V
/// @param[in] bc #b by #W list of boundary values
/// @param[in,out] data object containing options, initial guess --> solution and results
/// @param[out] W #V by #W list of *unnormalized* weights to normalize use
/// igl::normalize_row_sums(W,W);
/// @return true on success, false on failure
template <
typename DerivedV,
typename DerivedEle,
@@ -61,10 +60,10 @@ namespace igl
typename Derivedbc,
typename DerivedW>
IGL_INLINE bool bbw(
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedEle> & Ele,
const Eigen::PlainObjectBase<Derivedb> & b,
const Eigen::PlainObjectBase<Derivedbc> & bc,
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedEle> & Ele,
const Eigen::MatrixBase<Derivedb> & b,
const Eigen::MatrixBase<Derivedbc> & bc,
BBWData & data,
Eigen::PlainObjectBase<DerivedW> & W);
}

View File

@@ -0,0 +1,75 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "bezier.h"
#include "PlainMatrix.h"
#include <cassert>
// Adapted from main.c accompanying
// An Algorithm for Automatically Fitting Digitized Curves
// by Philip J. Schneider
// from "Graphics Gems", Academic Press, 1990
template <typename DerivedV, typename DerivedP>
IGL_INLINE void igl::bezier(
const Eigen::MatrixBase<DerivedV> & V,
const typename DerivedV::Scalar t,
Eigen::PlainObjectBase<DerivedP> & P)
{
// working local copy
PlainMatrix<DerivedV> Vtemp = V;
int degree = Vtemp.rows()-1;
/* Triangle computation */
for (int i = 1; i <= degree; i++)
{
for (int j = 0; j <= degree-i; j++)
{
Vtemp.row(j) = ((1.0 - t) * Vtemp.row(j) + t * Vtemp.row(j+1)).eval();
}
}
P = Vtemp.row(0);
}
template <typename DerivedV, typename DerivedT, typename DerivedP>
IGL_INLINE void igl::bezier(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedT> & T,
Eigen::PlainObjectBase<DerivedP> & P)
{
P.resize(T.size(),V.cols());
for(int i = 0;i<T.size();i++)
{
Eigen::Matrix<typename DerivedV::Scalar,1,DerivedV::ColsAtCompileTime> Pi;
bezier(V,T(i),Pi);
P.row(i) = Pi;
}
}
template <typename VMat, typename DerivedT, typename DerivedP>
IGL_INLINE void igl::bezier(
const std::vector<VMat> & spline,
const Eigen::MatrixBase<DerivedT> & T,
Eigen::PlainObjectBase<DerivedP> & P)
{
if(spline.size() == 0) return;
const int m = T.rows();
const int dim = spline[0].cols();
P.resize(m*spline.size(),dim);
for(int c = 0;c<spline.size();c++)
{
assert(dim == spline[c].cols() && "All curves must have same dimension");
DerivedP Pc;
bezier(spline[c],T,Pc);
P.block(m*c,0,m,dim) = Pc;
}
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template void igl::bezier<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::vector<Eigen::Matrix<double, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<double, -1, -1, 0, -1, -1> > > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template void igl::bezier<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template void igl::bezier<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 1, -1, 1, 1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> >&);
#endif

View File

@@ -0,0 +1,48 @@
#ifndef BEZIER_H
#define BEZIER_H
#include "igl_inline.h"
#include <Eigen/Core>
#include <vector>
namespace igl
{
/// Evaluate a polynomial Bezier Curve at single parameter value.
///
/// @param[in] V #V by dim list of Bezier control points
/// @param[in] t evaluation parameter within [0,1]
/// @param[out] P 1 by dim output point
template <typename DerivedV, typename DerivedP>
IGL_INLINE void bezier(
const Eigen::MatrixBase<DerivedV> & V,
const typename DerivedV::Scalar t,
Eigen::PlainObjectBase<DerivedP> & P);
/// Evaluate a polynomial Bezier Curve at many parameter values.
///
/// @param[in] V #V by dim list of Bezier control points
/// @param[in] T #T evaluation parameters within [0,1]
/// @param[out] P #T by dim output points
template <typename DerivedV, typename DerivedT, typename DerivedP>
IGL_INLINE void bezier(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedT> & T,
Eigen::PlainObjectBase<DerivedP> & P);
/// Evaluate a polynomial Bezier spline with a fixed parameter set for each
/// sub-curve.
///
/// @tparam VMat type of matrix of each list of control points
/// @tparam DerivedT Derived type of evaluation parameters
/// @tparam DerivedP Derived type of output points
/// @param[in] spline #curves list of lists of Bezier control points
/// @param[in] T #T evaluation parameters within [0,1] to use for each spline
/// @param[out] P #curves*#T by dim output points
template <typename VMat, typename DerivedT, typename DerivedP>
IGL_INLINE void bezier(
const std::vector<VMat> & spline,
const Eigen::MatrixBase<DerivedT> & T,
Eigen::PlainObjectBase<DerivedP> & P);
}
#ifndef IGL_STATIC_LIBRARY
# include "bezier.cpp"
#endif
#endif

View File

@@ -59,7 +59,7 @@ template <
typename DType,
typename PType>
IGL_INLINE void igl::bfs(
const Eigen::SparseMatrix<AType> & A,
const Eigen::SparseCompressedBase<AType> & A,
const size_t s,
std::vector<DType> & D,
std::vector<PType> & P)
@@ -83,7 +83,7 @@ IGL_INLINE void igl::bfs(
D.push_back(f);
P[f] = p;
seen[f] = true;
for(typename Eigen::SparseMatrix<AType>::InnerIterator it (A,f); it; ++it)
for(typename AType::InnerIterator it (A,f); it; ++it)
{
if(it.value()) Q.push({it.index(),f});
}

View File

@@ -6,18 +6,16 @@
#include <Eigen/Sparse>
namespace igl
{
// Traverse a **directed** graph represented by an adjacency list using
// breadth first search
//
// Inputs:
// A #V list of adjacency lists or #V by #V adjacency matrix
// s starting node (index into A)
// Outputs:
// D #V list of indices into rows of A in the order in which graph nodes
// are discovered.
// P #V list of indices into rows of A of predecessor in resulting
// spanning tree {-1 indicates root/not discovered), order corresponds to
// V **not** D.
/// Traverse a **directed** graph represented by an adjacency list using.
/// breadth first search; outputs Eigen types.
///
/// @param[in] A #V list of adjacency lists or #V by #V adjacency matrix
/// @param[in] s starting node (index into A)
/// @param[out] D #V list of indices into rows of A in the order in which graph nodes
/// are discovered.
/// @param[out] P #V list of indices into rows of A of predecessor in resulting
/// spanning tree {-1 indicates root/not discovered), order corresponds to
/// V **not** D.
template <
typename AType,
typename DerivedD,
@@ -28,6 +26,16 @@ namespace igl
Eigen::PlainObjectBase<DerivedD> & D,
Eigen::PlainObjectBase<DerivedP> & P);
/// Traverse a **directed** graph represented by an adjacency list using.
/// breadth first search; inputs adjacency lists, outputs lists.
///
/// @param[in] A #V list of adjacency lists
/// @param[in] s starting node (index into A)
/// @param[out] D #V list of indices into rows of A in the order in which graph nodes
/// are discovered.
/// @param[out] P #V list of indices into rows of A of predecessor in resulting
/// spanning tree {-1 indicates root/not discovered), order corresponds to
/// V **not** D.
template <
typename AType,
typename DType,
@@ -37,12 +45,13 @@ namespace igl
const size_t s,
std::vector<DType> & D,
std::vector<PType> & P);
/// \overload
template <
typename AType,
typename DType,
typename PType>
IGL_INLINE void bfs(
const Eigen::SparseMatrix<AType> & A,
const Eigen::SparseCompressedBase<AType> & A,
const size_t s,
std::vector<DType> & D,
std::vector<PType> & P);

View File

@@ -7,18 +7,19 @@
// obtain one at http://mozilla.org/MPL/2.0/.
#include "bfs_orient.h"
#include "orientable_patches.h"
#include "parallel_for.h"
#include <Eigen/Sparse>
#include <queue>
template <typename DerivedF, typename DerivedFF, typename DerivedC>
IGL_INLINE void igl::bfs_orient(
const Eigen::PlainObjectBase<DerivedF> & F,
const Eigen::MatrixBase<DerivedF> & F,
Eigen::PlainObjectBase<DerivedFF> & FF,
Eigen::PlainObjectBase<DerivedC> & C)
{
using namespace Eigen;
using namespace std;
SparseMatrix<int> A;
SparseMatrix<typename DerivedF::Scalar> A;
orientable_patches(F,C,A);
// number of faces
@@ -30,15 +31,14 @@ IGL_INLINE void igl::bfs_orient(
// Edge sets
const int ES[3][2] = {{1,2},{2,0},{0,1}};
if(&FF != &F)
if(((void*)&FF) != ((void*)&F))
{
FF = F;
}
// loop over patches
#pragma omp parallel for
for(int c = 0;c<num_cc;c++)
parallel_for(num_cc,[&](const int c)
{
queue<int> Q;
queue<typename DerivedF::Scalar> Q;
// find first member of patch c
for(int f = 0;f<FF.rows();f++)
{
@@ -51,7 +51,7 @@ IGL_INLINE void igl::bfs_orient(
assert(!Q.empty());
while(!Q.empty())
{
const int f = Q.front();
const typename DerivedF::Scalar f = Q.front();
Q.pop();
if(seen(f) > 0)
{
@@ -59,7 +59,7 @@ IGL_INLINE void igl::bfs_orient(
}
seen(f)++;
// loop over neighbors of f
for(typename SparseMatrix<int>::InnerIterator it (A,f); it; ++it)
for(typename SparseMatrix<typename DerivedF::Scalar>::InnerIterator it (A,f); it; ++it)
{
// might be some lingering zeros, and skip self-adjacency
if(it.value() != 0 && it.row() != f)
@@ -89,12 +89,12 @@ IGL_INLINE void igl::bfs_orient(
}
}
}
}
},1000);
// make sure flip is OK if &FF = &F
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template void igl::bfs_orient<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::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 void igl::bfs_orient<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
#endif

View File

@@ -8,27 +8,22 @@
#ifndef IGL_BFS_ORIENT_H
#define IGL_BFS_ORIENT_H
#include <Eigen/Core>
#include <igl/igl_inline.h>
#include "igl_inline.h"
namespace igl
{
// Consistently orient faces in orientable patches using BFS
//
// F = bfs_orient(F,V);
//
// Inputs:
// F #F by 3 list of faces
// Outputs:
// FF #F by 3 list of faces (OK if same as F)
// C #F list of component ids
//
//
/// Consistently orient faces in orientable patches using BFS.
///
/// @param[in] F #F by 3 list of faces
/// @param[out] FF #F by 3 list of faces (OK if same as F)
/// @param[out] C #F list of component ids
///
template <typename DerivedF, typename DerivedFF, typename DerivedC>
IGL_INLINE void bfs_orient(
const Eigen::PlainObjectBase<DerivedF> & F,
const Eigen::MatrixBase<DerivedF> & F,
Eigen::PlainObjectBase<DerivedFF> & FF,
Eigen::PlainObjectBase<DerivedC> & C);
};
}
#ifndef IGL_STATIC_LIBRARY
# include "bfs_orient.cpp"
#endif

View File

@@ -22,8 +22,8 @@ template <
typename SType,
typename DerivedW>
IGL_INLINE bool igl::biharmonic_coordinates(
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedT> & T,
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedT> & T,
const std::vector<std::vector<SType> > & S,
Eigen::PlainObjectBase<DerivedW> & W)
{
@@ -36,32 +36,36 @@ template <
typename SType,
typename DerivedW>
IGL_INLINE bool igl::biharmonic_coordinates(
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedT> & T,
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedT> & T,
const std::vector<std::vector<SType> > & S,
const int k,
Eigen::PlainObjectBase<DerivedW> & W)
{
using namespace Eigen;
using namespace std;
typedef typename DerivedV::Scalar Scalar;
typedef typename DerivedT::Scalar Integer;
// This is not the most efficient way to build A, but follows "Linear
// Subspace Design for Real-Time Shape Deformation" [Wang et al. 2015].
SparseMatrix<double> A;
SparseMatrix<Scalar> A;
{
DiagonalMatrix<double,Dynamic> Minv;
SparseMatrix<double> L,K;
DiagonalMatrix<Scalar, Dynamic> Minv;
SparseMatrix<Scalar> L, K;
Array<bool,Dynamic,Dynamic> C;
{
Array<bool,Dynamic,1> I;
on_boundary(T,I,C);
}
#ifdef false
#ifdef false
// Version described in paper is "wrong"
// http://www.cs.toronto.edu/~jacobson/images/error-in-linear-subspace-design-for-real-time-shape-deformation-2017-wang-et-al.pdf
SparseMatrix<double> N,Z,M;
SparseMatrix<Scalar> N, Z, M;
normal_derivative(V,T,N);
{
std::vector<Triplet<double> >ZIJV;
std::vector<Triplet<Scalar>> ZIJV;
for(int t =0;t<T.rows();t++)
{
for(int f =0;f<T.cols();f++)
@@ -84,37 +88,37 @@ IGL_INLINE bool igl::biharmonic_coordinates(
K = N+L;
massmatrix(V,T,MASSMATRIX_TYPE_DEFAULT,M);
// normalize
M /= ((VectorXd)M.diagonal()).array().abs().maxCoeff();
M /= ((Matrix<Scalar, Dynamic, 1>)M.diagonal()).array().abs().maxCoeff();
Minv =
((VectorXd)M.diagonal().array().inverse()).asDiagonal();
((Matrix<Scalar, Dynamic, 1>)M.diagonal().array().inverse()).asDiagonal();
#else
Eigen::SparseMatrix<double> M;
Eigen::MatrixXi E;
Eigen::VectorXi EMAP;
Eigen::SparseMatrix<Scalar> M;
Eigen::Matrix<Integer, Dynamic, Dynamic> E;
Eigen::Matrix<Integer, Dynamic, 1> EMAP;
crouzeix_raviart_massmatrix(V,T,M,E,EMAP);
crouzeix_raviart_cotmatrix(V,T,E,EMAP,L);
// Ad #E by #V facet-vertex incidence matrix
Eigen::SparseMatrix<double> Ad(E.rows(),V.rows());
Eigen::SparseMatrix<Scalar> Ad(E.rows(),V.rows());
{
std::vector<Eigen::Triplet<double> > AIJV(E.size());
std::vector<Eigen::Triplet<Scalar>> AIJV(E.size());
for(int e = 0;e<E.rows();e++)
{
for(int c = 0;c<E.cols();c++)
{
AIJV[e+c*E.rows()] = Eigen::Triplet<double>(e,E(e,c),1);
AIJV[e + c * E.rows()] = Eigen::Triplet<Scalar>(e, E(e, c), 1);
}
}
Ad.setFromTriplets(AIJV.begin(),AIJV.end());
}
// Degrees
Eigen::VectorXd De;
Eigen::Matrix<Scalar, Dynamic, 1> De;
sum(Ad,2,De);
Eigen::DiagonalMatrix<double,Eigen::Dynamic> De_diag =
Eigen::DiagonalMatrix<Scalar,Eigen::Dynamic> De_diag =
De.array().inverse().matrix().asDiagonal();
K = L*(De_diag*Ad);
// normalize
M /= ((VectorXd)M.diagonal()).array().abs().maxCoeff();
Minv = ((VectorXd)M.diagonal().array().inverse()).asDiagonal();
M /= ((Matrix<Scalar, Dynamic, 1>)M.diagonal()).array().abs().maxCoeff();
Minv = ((Matrix<Scalar, Dynamic, 1>)M.diagonal().array().inverse()).asDiagonal();
// kill boundary edges
for(int f = 0;f<T.rows();f++)
{
@@ -145,7 +149,7 @@ IGL_INLINE bool igl::biharmonic_coordinates(
}
// Vertices in point handles
const size_t mp =
count_if(S.begin(),S.end(),[](const vector<int> & h){return h.size()==1;});
count_if(S.begin(),S.end(),[](const vector<SType> & h){return h.size()==1;});
// number of region handles
const size_t r = S.size()-mp;
// Vertices in region handles
@@ -159,9 +163,9 @@ IGL_INLINE bool igl::biharmonic_coordinates(
}
const size_t dim = T.cols()-1;
// Might as well be dense... I think...
MatrixXd J = MatrixXd::Zero(mp+mr,mp+r*(dim+1));
VectorXi b(mp+mr);
MatrixXd H(mp+r*(dim+1),dim);
Matrix<Scalar, Dynamic, Dynamic> J = Matrix<Scalar, Dynamic, Dynamic>::Zero(mp+mr,mp+r*(dim+1));
Matrix<Integer, Dynamic, 1> b(mp+mr);
Matrix<Scalar, Dynamic, Dynamic> H(mp+r*(dim+1),dim);
{
int v = 0;
int c = 0;
@@ -194,10 +198,10 @@ IGL_INLINE bool igl::biharmonic_coordinates(
// minimize ½ W' A W'
// subject to W(b,:) = J
return min_quad_with_fixed(
A,VectorXd::Zero(A.rows()).eval(),b,J,SparseMatrix<double>(),VectorXd(),true,W);
A,Matrix<Scalar, Dynamic, 1>::Zero(A.rows()).eval(),b,J,SparseMatrix<Scalar>(),Matrix<Scalar, Dynamic, 1>(),true,W);
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template bool igl::biharmonic_coordinates<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::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&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template bool igl::biharmonic_coordinates<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
#endif

View File

@@ -12,73 +12,73 @@
#include <vector>
namespace igl
{
// Compute "discrete biharmonic generalized barycentric coordinates" as
// described in "Linear Subspace Design for Real-Time Shape Deformation"
// [Wang et al. 2015]. Not to be confused with "Bounded Biharmonic Weights
// for Real-Time Deformation" [Jacobson et al. 2011] or "Biharmonic
// Coordinates" (2D complex barycentric coordinates) [Weber et al. 2012].
// These weights minimize a discrete version of the squared Laplacian energy
// subject to positional interpolation constraints at selected vertices
// (point handles) and transformation interpolation constraints at regions
// (region handles).
//
// Templates:
// HType should be a simple index type e.g. `int`,`size_t`
// Inputs:
// V #V by dim list of mesh vertex positions
// T #T by dim+1 list of / triangle indices into V if dim=2
// \ tetrahedron indices into V if dim=3
// S #point-handles+#region-handles list of lists of selected vertices for
// each handle. Point handles should have singleton lists and region
// handles should have lists of size at least dim+1 (and these points
// should be in general position).
// Outputs:
// W #V by #points-handles+(#region-handles * dim+1) matrix of weights so
// that columns correspond to each handles generalized barycentric
// coordinates (for point-handles) or animation space weights (for region
// handles).
// returns true only on success
//
// Example:
//
// MatrixXd W;
// igl::biharmonic_coordinates(V,F,S,W);
// const size_t dim = T.cols()-1;
// MatrixXd H(W.cols(),dim);
// {
// int c = 0;
// for(int h = 0;h<S.size();h++)
// {
// if(S[h].size()==1)
// {
// H.row(c++) = V.block(S[h][0],0,1,dim);
// }else
// {
// H.block(c,0,dim+1,dim).setIdentity();
// c+=dim+1;
// }
// }
// }
// assert( (V-(W*H)).array().maxCoeff() < 1e-7 );
/// Compute "discrete biharmonic generalized barycentric coordinates" as
/// described in "Linear Subspace Design for Real-Time Shape Deformation"
/// [Wang et al. 2015]. Not to be confused with "Bounded Biharmonic Weights
/// for Real-Time Deformation" [Jacobson et al. 2011] or "Biharmonic
/// Coordinates" (2D complex barycentric coordinates) [Weber et al. 2012].
/// These weights minimize a discrete version of the squared Laplacian energy
/// subject to positional interpolation constraints at selected vertices
/// (point handles) and transformation interpolation constraints at regions
/// (region handles).
///
/// @tparam SType should be a simple index type e.g. `int`,`size_t`
/// @param[in] V #V by dim list of mesh vertex positions
/// @param[in] T #T by dim+1 list of / triangle indices into V if dim=2
/// \ tetrahedron indices into V if dim=3
/// @param[in] S #point-handles+#region-handles list of lists of selected vertices for
/// each handle. Point handles should have singleton lists and region
/// handles should have lists of size at least dim+1 (and these points
/// should be in general position).
/// @param[out] W #V by #points-handles+(#region-handles * dim+1) matrix of weights so
/// that columns correspond to each handles generalized barycentric
/// coordinates (for point-handles) or animation space weights (for region
/// handles).
/// @return true only on success
///
/// #### Example:
///
/// \code{cpp}
/// MatrixXd W;
/// igl::biharmonic_coordinates(V,F,S,W);
/// const size_t dim = T.cols()-1;
/// MatrixXd H(W.cols(),dim);
/// {
/// int c = 0;
/// for(int h = 0;h<S.size();h++)
/// {
/// if(S[h].size()==1)
/// {
/// H.row(c++) = V.block(S[h][0],0,1,dim);
/// }else
/// {
/// H.block(c,0,dim+1,dim).setIdentity();
/// c+=dim+1;
/// }
/// }
/// }
/// assert( (V-(W*H)).array().maxCoeff() < 1e-7 );
/// \endcode
template <
typename DerivedV,
typename DerivedT,
typename SType,
typename DerivedW>
IGL_INLINE bool biharmonic_coordinates(
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedT> & T,
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedT> & T,
const std::vector<std::vector<SType> > & S,
Eigen::PlainObjectBase<DerivedW> & W);
// k 2-->biharmonic, 3-->triharmonic
/// \overload
/// @param[in] k power of Laplacian (experimental)
template <
typename DerivedV,
typename DerivedT,
typename SType,
typename DerivedW>
IGL_INLINE bool biharmonic_coordinates(
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedT> & T,
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedT> & T,
const std::vector<std::vector<SType> > & S,
const int k,
Eigen::PlainObjectBase<DerivedW> & W);

Some files were not shown because too many files have changed in this diff Show More