mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-05-14 00:52:04 +00:00
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 *e3c277b9eeFor 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:
@@ -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()
|
||||
|
||||
16
deps_src/libigl/README-OrcaSlicer.md
Normal file
16
deps_src/libigl/README-OrcaSlicer.md
Normal 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
13
deps_src/libigl/README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# libigl - A simple C++ geometry processing library
|
||||
|
||||
[](https://github.com/libigl/libigl/actions?query=workflow%3ABuild+branch%3Amain+event%3Apush)
|
||||
[](https://anaconda.org/conda-forge/igl)
|
||||
|
||||

|
||||
|
||||
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
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
19
deps_src/libigl/igl/COLLAPSE_EDGE_NULL.h
Normal file
19
deps_src/libigl/igl/COLLAPSE_EDGE_NULL.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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>();
|
||||
|
||||
7836
deps_src/libigl/igl/FastWindingNumberForSoups.h
Normal file
7836
deps_src/libigl/igl/FastWindingNumberForSoups.h
Normal file
File diff suppressed because it is too large
Load Diff
21
deps_src/libigl/igl/FileEncoding.h
Normal file
21
deps_src/libigl/igl/FileEncoding.h
Normal 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
|
||||
64
deps_src/libigl/igl/FileMemoryStream.h
Normal file
64
deps_src/libigl/igl/FileMemoryStream.h
Normal 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
9
deps_src/libigl/igl/IGL_ASSERT.h
Normal file
9
deps_src/libigl/igl/IGL_ASSERT.h
Normal 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
|
||||
@@ -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) {}
|
||||
|
||||
@@ -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(
|
||||
|
||||
26
deps_src/libigl/igl/MappingEnergyType.h
Normal file
26
deps_src/libigl/igl/MappingEnergyType.h
Normal 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
|
||||
@@ -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
|
||||
};
|
||||
};
|
||||
|
||||
497
deps_src/libigl/igl/MshLoader.cpp
Normal file
497
deps_src/libigl/igl/MshLoader.cpp
Normal 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));
|
||||
}
|
||||
}
|
||||
192
deps_src/libigl/igl/MshLoader.h
Normal file
192
deps_src/libigl/igl/MshLoader.h
Normal 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
|
||||
343
deps_src/libigl/igl/MshSaver.cpp
Normal file
343
deps_src/libigl/igl/MshSaver.cpp
Normal 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();
|
||||
}
|
||||
87
deps_src/libigl/igl/MshSaver.h
Normal file
87
deps_src/libigl/igl/MshSaver.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
95
deps_src/libigl/igl/PlainMatrix.h
Normal file
95
deps_src/libigl/igl/PlainMatrix.h
Normal 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
|
||||
36
deps_src/libigl/igl/PlainVector.h
Normal file
36
deps_src/libigl/igl/PlainVector.h
Normal 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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
namespace igl
|
||||
{
|
||||
/// @private
|
||||
// Simple Viewport class for an opengl context. Handles reshaping and mouse.
|
||||
struct Viewport
|
||||
{
|
||||
|
||||
@@ -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 <<
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
52
deps_src/libigl/igl/accumarray.cpp
Normal file
52
deps_src/libigl/igl/accumarray.cpp
Normal 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
|
||||
47
deps_src/libigl/igl/accumarray.h
Normal file
47
deps_src/libigl/igl/accumarray.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
69
deps_src/libigl/igl/average_from_edges_onto_vertices.cpp
Normal file
69
deps_src/libigl/igl/average_from_edges_onto_vertices.cpp
Normal 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
|
||||
38
deps_src/libigl/igl/average_from_edges_onto_vertices.h
Normal file
38
deps_src/libigl/igl/average_from_edges_onto_vertices.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
42
deps_src/libigl/igl/barycentric_interpolation.cpp
Normal file
42
deps_src/libigl/igl/barycentric_interpolation.cpp
Normal 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
|
||||
40
deps_src/libigl/igl/barycentric_interpolation.h
Normal file
40
deps_src/libigl/igl/barycentric_interpolation.h
Normal 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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
75
deps_src/libigl/igl/bezier.cpp
Normal file
75
deps_src/libigl/igl/bezier.cpp
Normal 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
|
||||
48
deps_src/libigl/igl/bezier.h
Normal file
48
deps_src/libigl/igl/bezier.h
Normal 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
|
||||
@@ -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});
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user