Compare commits

...
Author SHA1 Message Date
Alec Jacobson e0f3fe6688 better cm 2026-01-26 19:43:58 -05:00
Alec Jacobson 0e8f09a4f8 doc 2026-01-26 18:21:23 -05:00
Alec Jacobson a439f89d22 working spline winding number and demo 2026-01-26 17:11:02 -05:00
Alec Jacobson 2ecacc3c76 Orientation to igl::, point_in_convex_hull, eyt_winding_number with func handle, fix bug in eyt_sdf, tutorial, tests 2026-01-26 12:13:43 -05:00
Alec Jacobson 0496a74ed7 roots, cubics, tests and tutorial 2026-01-24 23:27:28 -05:00
Nicolas Ulrich 7313592e16 Add missing #include <cassert> (#2521) 2026-01-16 16:49:44 -05:00
Alec Jacobson 2282ec8018 accelerated 2D winding number (and sdf in example) (#2522)
* accelerated 2D winding number (and sdf in example)

* line width [ci skip]

* empty
2026-01-16 16:49:21 -05:00
Alec Jacobson fdddfa2b6e 503_ARAPParam: take input path from arg if present (#2524) 2026-01-16 16:49:01 -05:00
Sven-Kristofer PilzandAlec Jacobson 95ec606b70 Reduce mallocs in principal_curvature. (#2497)
Co-authored-by: Alec Jacobson <alecjacobson@gmail.com>
2026-01-10 17:35:56 -05:00
Alec JacobsonandxTree cd73f3a4f3 add templates for planarize_quad_mesh (#2512)
* add templates for `planarize_quad_mesh`

* templates in subroutine

* xcode version in ci

---------

Co-authored-by: xTree <xliotx@gmail.com>
2025-11-12 15:12:16 -05:00
Rob McDonald ae8f959ea2 Force codesign to sign binaries, even if they are already signed (#2494)
For some reason, Apple binaries need to be signed, but sometimes are already signed.  This triggers an error in codesign unless the force (-f) flag is passed.
2025-08-01 12:16:58 -04:00
Alec Jacobson b0aa5f2a1c Orient2d vectorized (#2492) [skip ci]
* orient2d

* missing include

* missing include

* fix include
2025-07-28 13:49:05 -04:00
Alec Jacobson 09e1598e6d Minimal AABB tree + SDFs + Variable Radius Offsets (#2490)
* working eytzinger aabb

* working and reasonably efficient variable radius offset

* working example

* comments

* better key commands

* bad includes, defines

* missing sign function; test
2025-07-21 22:35:34 -04:00
Alec Jacobson 678e1fff76 fix bad templating breaking python build (#2489)
* fix bad templating breaking python build

* assumed int when python using Integer
2025-07-16 22:47:15 -04:00
Alec Jacobson 47b557df58 Lipschitz octree pruning (#2488) [skip ci]
* lipshitz_octree tutorial example

* better comments

* revert to shallow default

* better names and documentation, dont return I

* long long -> std::int64_t

* asdd tutorail chapter 10

* precious windows

* int64_t -> std::int64_t

* batch version

* fix template chain from overzealous index typing

* bump to c++17 (if constexpr)
2025-07-16 21:20:22 -04:00
Alec JacobsonandBruegelN 182e36df24 No longer using namespace std; and using namespace Eigen; to avoid issues with other libs (#2483)
* remove `using namespace std;` and fix resulting errors with missing namespaces

* remove `using namespace Eigen;` and fix resulting errors with missing namespaces

This should fix issues like https://github.com/libigl/libigl/issues/2480

* Add missing namespaces

fixup for 9ef213ba34
fixup for 3e88aa04fd

* missing Eigen::

* missing std::

* more missing std::

---------

Co-authored-by: BruegelN <bruegeln@crashing.systems>
2025-06-24 09:22:16 -04:00
Alec Jacobson bf9bdb9c70 pressing N,n changes lighting to pseudocolored normals (#2478) 2025-06-23 17:25:10 -04:00
Alec Jacobson 73a2e0de9b split functions into files; add vectorized orient3d (#2479) 2025-06-16 09:47:46 -04:00
Alec Jacobson 8866f214a0 crashing unless Epick is used 2025-05-23 14:16:46 -04:00
Alec Jacobson cf9ed7f492 Super Fibonacci and Oriented Bounding Boxes (#2472) [skip ci]
* add codesign for mac execs

* better ifdef guard

* simple brute force obb

* wrapper on cgals obb

* tutorial for OBB

* minimal test

* minimal test

* note

* use igl::PI

* expose quantity to optimize over
2025-05-23 10:57:22 -04:00
Peizhuo LiandAlec Jacobson 40e7900ccb Fix dqs not checking if quaternions are on the same hemisphere (#2390)
Co-authored-by: Alec Jacobson <alecjacobson@gmail.com>
2025-05-14 23:21:03 -04:00
NevsorandAlec Jacobson b443ac0261 Fix "Assertion failed" when calling igl::heat_geodesics_precompute using a V with fixed column count (#2419) [skip ci]
* Fix bug where `igl::heat_geodesics_precompute` will fail for `V` with a fixed number of columns.

See https://github.com/libigl/libigl/issues/2418

* Add missing call to .transpose()

---------

Co-authored-by: Alec Jacobson <alecjacobson@gmail.com>
2025-05-14 23:05:22 -04:00
Siqi WangandAlec Jacobson b286e13ac6 Update extract_non_manifold_edge_curves.cpp (#2423) [skip ci]
Co-authored-by: Alec Jacobson <alecjacobson@gmail.com>
2025-05-14 22:59:25 -04:00
Flo e91ffcb549 dijkstra: Fix inconsistent typing (#2469) [skip ci] 2025-05-14 22:37:48 -04:00
nicolas hsu d9524ade53 laplace equation tutorial - fixed bug with slice/lazy eval (#2447) [ci-skip] 2025-05-14 21:29:56 -04:00
Jérémie Dumas 89267b4a80 Use box-drawing characters in comments. (#2466) 2025-04-25 13:20:51 -07:00
Jérémie Dumas 7c3c05d637 Update ubuntu image (#2467) 2025-04-25 11:24:24 -07:00
Alec Jacobson 7888711039 bump deps (#2462) 2025-04-15 09:35:58 -04:00
Alec JacobsonandAlec Jacobson 08be0704c2 bump embree 4 and missing template (#2460)
* add missing template

* bump embree

---------

Co-authored-by: Alec Jacobson <ajx@mac.lan>
2025-04-07 17:23:22 -04:00
Alec Jacobson 0e360d5250 Revert templating on collapse_edge, separate overloads (#2455)
* Fix 2452

* fix cachev2 issue?

* and the windows ❄️

* removed __1::

* fix tutorial to use new func

* cmake bullshit
2025-03-31 17:00:36 -04:00
Alec Jacobson 5e561c28c8 Update isolines.h doc [ci skip] 2025-03-28 11:15:45 -04:00
Alec Jacobson 25d63024bb [ci skip] improve doc 2025-03-18 19:40:46 -04:00
Alec Jacobson f85a3c76db [ci skip] improve doc 2025-03-18 19:40:05 -04:00
Alec Jacobson 0c9c8cd643 Merge branch 'main' of github.com:libigl/libigl 2025-03-18 19:39:44 -04:00
Alec Jacobson a72b9386c8 [ci skip] improve doc 2025-03-18 19:39:38 -04:00
DJAntivenom ba69acc509 Fix division type error for highdpi calculation (#2386)
The way the highdpi value was calculated could lead to it being set to 0 or inf for certain types of window managers.
(Tiling window managers). This was caused by it trying to resize the window to a width and height of 0x0, or by having
the logical width/height of the window be smaller than the pyhsical one. This would cause the `highdpi` variable to be
set to 0, which would later cause a glfw call to be made with `inf` as an argument.
2025-02-18 08:36:41 -05:00
evouga a221faf1e4 Update voxel_grid.h (#2441)
Clarify the documentation
2025-01-07 18:50:48 -05:00
Alec Jacobson 69e2b7ee67 Fix Derived in heat_geodesics; boost url (#2440)
* PlainObject -> MatrixBase

* template igl::Hit

* vector input intersect rays with multiple hits

* initialize

* initialize

* only write if hit

* fix templates

* template me baby

* templates

* my god. so many PlainObject -> Matrix; Derived -> PlainMatrix<Derived>

* Options doesn't exist for Maps/Refs

* templates; windows size_t shinanigans

* Derived->PlainMatrix

* windows template

* derived -> plainvector

* options

* fix templating

* std types

* fix windingnumbertree tempalting

* further fix windingnumbertree tempalting

* Xi->XI

* templating

* clean up and template some of the decimation code; eventually gave up on templating outer functions

* rm needless cast

* attempt to fix index templating in boolean code

* remove debugging casts

* more templatin hell

* debug kruft

* vector resize

* assert

* int -> template

* int -> template

* int -> template

* templating away more Xi

* templating away more 3i

* formatting

* vector

* plainmatrix

* plainmatrix

* bug

* templating MSH io

* remove use of Map

* zero default tags

* bug fix

* file debug flags

* __1::

* better typing

* knn tempalte

* note

* templating

* reorder scaf inputs

* fix build

* doc

* templates

* messier than I thought

* doc

* Xi -> XI

* use templated type

* 1x1 is always symmetric

* use index type

* split intrinsic

* templating

* template internal

* restore boost link

* actually add the change to hg
2025-01-07 18:50:16 -05:00
Alec Jacobson 667101084a Add support for maintaining segments during refinement (#2424)
* segment control

* typos
2024-12-20 11:12:35 -05:00
Alec Jacobson 7472691fe6 PlainObject -> MatrixBase (#2425)
* PlainObject -> MatrixBase

* template igl::Hit

* vector input intersect rays with multiple hits

* initialize

* initialize

* only write if hit

* fix templates

* template me baby

* templates

* my god. so many PlainObject -> Matrix; Derived -> PlainMatrix<Derived>

* Options doesn't exist for Maps/Refs

* templates; windows size_t shinanigans

* Derived->PlainMatrix

* windows template

* derived -> plainvector

* options

* fix templating

* std types

* fix windingnumbertree tempalting

* further fix windingnumbertree tempalting

* Xi->XI

* templating

* clean up and template some of the decimation code; eventually gave up on templating outer functions

* rm needless cast

* attempt to fix index templating in boolean code

* remove debugging casts

* more templatin hell

* debug kruft

* vector resize

* assert

* int -> template

* int -> template

* int -> template

* templating away more Xi

* templating away more 3i

* formatting

* vector

* plainmatrix

* plainmatrix

* bug

* templating MSH io

* remove use of Map

* zero default tags

* bug fix

* file debug flags

* __1::

* better typing

* knn tempalte

* note

* templating

* reorder scaf inputs

* fix build

* doc

* templates

* messier than I thought

* doc

* Xi -> XI

* use templated type

* 1x1 is always symmetric

* use index type

* split intrinsic

* templating

* template internal
2024-12-20 11:12:11 -05:00
Alf-André Walla 20c3ee0740 Add missing include <cassert> in AABB.h (#2432) 2024-12-06 14:52:26 -05:00
Alec Jacobson 5067c8b7eb bump cgal, boost; rm gmp, mpfr (#2431)
* bump cgal; boost; mpf4; (mpfr+gmp may no longer be needed)

* actually use boost from cmake

* rm gmp mpfr 🎉

* try to tell cgal to use boost

* explicitly disable gmp

* rm gmp templates

* actually remove them
2024-11-26 22:30:10 -05:00
Alec Jacobson c2f96e8e18 improved docs 2024-11-07 08:28:37 -05:00
Alec Jacobson f962e4a6b6 Support Batched Marching Cubes (#2422)
* Working example; need to change name rather than overwrite 705

* separate tutorial for batch

* comment
2024-10-28 11:25:43 -04:00
Alec Jacobson 5d93f800ba fix warnings for Eigen's 'convenience' type all (#2421) 2024-10-28 11:25:29 -04:00
Martin Heistermann 8aca5bd0c4 Eigen build fix, Eigen::all has been renamed: (#2399)
Replace deprecated/removed Eigen::all with Eigen::placeholders:all.
2024-10-28 09:19:00 -04:00
Jérémie Dumas fac5d4a01d Change arg to const & to avoid MSan issue. (#2415) 2024-09-27 07:52:34 -04:00
Alec Jacobson 0e02103df7 add refine functionality for triangle wrapper (#2402) 2024-07-18 12:38:47 -04:00
Alec Jacobson dd9654a476 allow shared edge to be conflictingly oriented (#2395) 2024-06-13 09:08:10 -04:00
Alec Jacobson 01f2dc0a60 Add and fix test for fast_find_self_intersections (#2382)
* add test case

* add coplanarity test

* another failing test

* use orient3d

* no printing

* reverting... That introduced lots of other failure cases

* subdivided knight case

* wip predicates

* promising predicates version

* tri_tri_overlap compiles, header guards, predicate find_*

* tests for predicates::find_in...

* parallel for

* note

* mv to predicates

* remove old functions

* tutorials; extracting segments is broken 904

* fix extraction bug

* missing header

* capture consts
2024-05-03 12:01:17 -04:00
Alec Jacobson 8afe66e8fd fix static bug (#2380) 2024-05-02 22:34:41 -04:00
Alec Jacobson 6e32964a82 Fix CI Build: avoid test on windows, remove Comiso module, specific xcode on github (#2384)
* just avoid failing test on windows 😔

* mayfil instead

* mac os x xcode bug fix

* rm bonus endif

* rm comiso
2024-04-29 14:42:12 -04:00
Alec JacobsonandAlec Jacobson dafd52343b fix merge of non shared edges (#2374)
Co-authored-by: Alec Jacobson <alecjacobson@adobe.com>
2024-04-15 13:28:17 -04:00
David Coeurjolly 36930e5d19 Fixing shadowed variable declaration (that may lead to a compiler error if -Werror=shadow) (#2366) 2024-03-28 08:34:42 -04:00
Alec JacobsonandAlec Jacobson b4d8556a6b hybrid mass matrix for tets (#2364)
Co-authored-by: Alec Jacobson <alecjacobson@adobe.com>
2024-03-18 23:53:46 -04:00
Alec JacobsonandAlec Jacobson 81180a6e6a Boundary facets orientation (#2362)
* fix boundary_facets orientation + test

* rm print in tests

---------

Co-authored-by: Alec Jacobson <alecjacobson@adobe.com>
2024-03-17 11:10:07 -04:00
Alec JacobsonandAlec Jacobson a8819dcf9b fix bug (#2361)
Co-authored-by: Alec Jacobson <alecjacobson@adobe.com>
2024-03-14 17:45:34 -04:00
Alec JacobsonandAlec Jacobson 1886d18147 fix debug bug (#2360)
Co-authored-by: Alec Jacobson <alecjacobson@adobe.com>
2024-03-07 20:16:48 -05:00
Alec Jacobson 7e6bf3b81c missing break (#2354) 2024-02-20 11:23:23 -05:00
Alec Jacobson c7a84522c3 CGAL tests don't seem to run on Windows CI builds (#2351)
* show all tests

* fix cmake target
2024-02-19 23:18:34 -05:00
Alec Jacobson fe65ecb907 remove or hide cerr<< behind ifdef (#2349) [ci skip] 2024-02-09 11:13:07 -05:00
William8915 33a931d019 Fix compile error on gcc-12.3 (#2336)
This is a follow up fix of #2254. After #2254 gcc-12.3 reports the error "template-id not allowed for destructor".
2024-02-07 09:26:22 -05:00
Alec JacobsonandAlec Jacobson 94c6afde11 fix bug where cost of collapsed edge was attempted (#2347)
Co-authored-by: Alec Jacobson <alecjacobson@adobe.com>
2024-02-07 09:25:54 -05:00
Alec Jacobson 8185a213d0 centroid only worked for fixed size input (#2340)
* template for variable size and failing test

* fix

* static asserts
2024-01-23 20:14:49 -05:00
Alec JacobsonandAlec Jacobson 7d1614af1e Fix split_nonmanifold (#2344)
* failing test

* simply cut along all non-manifold edges

* fix compile

* before rewrite

* after rewrite

---------

Co-authored-by: Alec Jacobson <alecjacobson@adobe.com>
2024-01-23 09:25:44 -05:00
Bryn LloydandBryn Lloyd 293e79ff86 enable mixed polygons using convention that negative indices are ignored (#2338)
* enable mixed polygons using convention that negative indices are ignored

* add unit tests

---------

Co-authored-by: Bryn Lloyd <lloyd@itis.swiss>
2024-01-17 10:36:24 -05:00
Alec Jacobson 37f3b1d821 fix bug in cut_mesh; improve documentation; add test (#2315) 2024-01-10 09:40:11 -05:00
Taylor Holliday a8b3833942 fix compile error (#2328)
* Update eigs.cpp

Reduce terminal spew

* Revert "Update eigs.cpp"

This reverts commit fdbdb42934.

* Fix compile error and propagate errors
2024-01-10 09:39:41 -05:00
Alec JacobsonandAlec Jacobson 7f7f0fe007 use our boost-cmake which uses slow, non-jfrog url (#2330)
Co-authored-by: Alec Jacobson <alecjacobson@adobe.com>
2024-01-08 18:06:08 -05:00
Alec Jacobson 0b9030b1ed wrong header 2023-10-23 08:25:36 -04:00
Alec JacobsonandAlec Jacobson 112c1b8e48 Dynamic updates to AABB tree; intersection-blocking mesh decimation (#2301)
* working insertion and rotation b-b-b-but pointers aren't stuck to m_primitive

* insert now maintains primitive's pointers;+rotate is now getting heights in right ballpark

* sibling rotations working (and helping); dry run test working (and helping)

* working insertion, deletion (detach), and refit with padding.

* working; inexact

* working; inexact

* working; inexact

* note about poor assumptions

* working well after bug fixes. before refactor into functions

* simple self-intersection test function

* moved all functions to files

* docs

* blocking directly in qslim. better docs. aabb templates/tests;

* dont use size_t and fix namespace

* brute-force too fast on linux

* rm overloads in qslim/decimate; cgal template

* fix coplanar bug; factor out raytri.c

* fix and cgal debug

* refactor fast_find; fix bugs in fast_find; fix bugs in shared_vertex

* tutorials running again

* cleaned up aabb tutorials; templates

* format docs

* docs. arg names

* template name

* improve docs

* debugging test

* debugging test

* debugging test

* debugging test

* debugging test

* debugging test

* debugging test

* debugging test

* ebuggin test

* ebuggin test

* add epsilon to ray_triangle ifs

* erroneous includes

* rm leftover includes

* fix cmake bug

* uh actually fix cmake bug

* missing delete

* simple insert test

* don't pad all leaves F.rows() times

* fix pad bug

---------

Co-authored-by: Alec Jacobson <alecjacobson@adobe.com>
2023-10-14 07:32:50 -04:00
Alec Jacobson 7c9387c92b prefer std::u?int[0-9]+_t and include <cstdint> else include <stdint.h> (#2302) 2023-10-13 20:15:17 -04:00
Alec Jacobson 1c8c6d38ba Stay up to date with stable (#2300)
* bump version in cmake

* fix aassertions, add templates to compile in debug (#2299)
2023-10-06 19:47:53 -04:00
Alec JacobsonandAlec Jacobson 7991ee81d8 tata -> data (#2295) [ci skip]
Co-authored-by: Alec Jacobson <alecjacobson@adobe.com>
2023-09-28 13:12:57 -04:00
Alec Jacobson fdaac01bcc Fix AABB::find to not try to run 2D code on 3D input and vice versa (#2294) [ci skip]
* pull out DIM from find

* AABB find test

* templates
2023-09-26 21:39:36 -04:00
Alec Jacobson b4152c576c better docs (#2293) [ci skip] 2023-09-26 12:07:22 -04:00
Alec Jacobson 1b07ebcf9e rm vector overloads and simplify api (#2290) [ci skip] 2023-09-25 16:27:01 -04:00
Alec Jacobson 64c2740230 bump cgal to 5.6 (#2289) [ci skip] 2023-09-25 09:59:14 -04:00
Evan Barentin 2b05343e0d Normalize all the line endings (#2288) 2023-09-22 12:39:53 -04:00
Alec Jacobson 7547801f58 use unit vector atan formula; split intrinsic version (#2285) [ci skip]
* use unit vector atan formula; split intrinsic version

* fix on linux
2023-09-19 23:28:58 -04:00
Emmanuel OliviandAlec Jacobson d154f0587c Add test for issue/2270 and a fix (#2271)
* Add test for issue/2270 and a (dirty) fix

* restore func; simplify test (failing)

* more robust fix

* Implement solution from T.Ize in "Robust BVH Ray Traversal" 4.2

* Implement solution from T.Ize in "Robust BVH Ray Traversal" 4.1

* Move nextafter in its own file

* Add std:: to other nextafter calls

* Add test for nextafter

* Use unaryExpr for nextafter on Eigen elements

* Fix and rename into increment_ulp

* missing templates

* correct overload name; missing templates

---------

Co-authored-by: Alec Jacobson <alecjacobson@gmail.com>
2023-09-18 20:18:08 -04:00
Alec Jacobson dddfd92c7a Merge branch 'main' of github.com:libigl/libigl 2023-09-18 17:51:31 -04:00
Alec Jacobson 6ddf3b0dd7 better documentation [ci skip] 2023-09-18 17:51:26 -04:00
Alec Jacobson e139702373 writeOFF for quads etc. (#2283) [ci skip] 2023-09-18 17:01:12 -04:00
Alec Jacobson fe8e17c095 add gitattributes file (#2282) [ci skip] 2023-09-18 17:00:35 -04:00
Alec Jacobson 0c78def493 Custom Shader tutorial (#2281) [ci skip] 2023-09-18 17:00:16 -04:00
Alec Jacobson 3c0f31f132 better templates for marching tets (#2279) [ci skip]
* better templates

* fabs -> abs

* missing cast
2023-09-18 15:07:26 -04:00
Alec Jacobson 2b62322cd5 improve color doc [ci skip] 2023-09-18 14:33:46 -04:00
Alec Jacobson cb111f6838 Bump to OpenGL version 4.1 (#2277)
* bump glad

* fix name changes

* remove compilation guards

* bump runtime to 4.1 too

* fix map_texture; template bind

* doc

* attempt to skip tests

* that didnt work, disable with cmake

* missing template

* rm __1::
2023-09-14 22:29:44 -04:00
Alec Jacobson 68684132e5 adj list fix unref; manifold doc; icosa; tests (#2276) [ci skip] 2023-09-13 18:27:47 -04:00
Alec Jacobson 0c1865a8d6 Fix bug in half_space_box (#2269) [ci skip]
* test

* fix 1384 and add test
2023-09-09 00:12:46 -04:00
Alec Jacobson 5dcce37c9d rm empty ifdef [ci skip] 2023-09-08 20:51:35 -04:00
Alec Jacobson d6448a86fb 3 new trimming methods and tutorial (#2268) [ci skip]
* 3 new trimming methods and tutorial

* missing template

* rm warning

* add tests

* Windows templates
2023-09-08 12:58:07 -04:00
HomayoonT 6a31dbf126 Update MeshGL.h (#2267) [ci skip]
Added #include <cstdint> for fixing build failure mingw-w64 "w64devkit"
2023-09-07 12:12:07 -04:00
Alec Jacobson 321d0d8ed0 Fix most floating point exceptions (#2266)
* better documentation, test against eigen slicing

* remove a bunch of slices

* clean up templates; static asserts on vector types

* final purges of slice

* fix templates in debug and ears test

* fix slice mask bug

* fix slice bug

* fix most fpe exceptions

* fix limit case

* more robust push, pop
2023-09-06 23:25:28 -04:00
Alec Jacobson 9bfacf8fb6 fix slim doublearea -> volume for tets (#2262) [ci skip] 2023-09-04 10:00:16 -04:00
Alec Jacobson f48c5a93f1 Fix 1462 2023-09-03 21:59:57 -04:00
Alec Jacobson d326251896 fix moments to work with more input types 2023-09-03 14:59:57 -04:00
Alec Jacobson 74160c4c1c sitemap xml; link to functions list 2023-09-02 10:44:09 -04:00
Alec Jacobson b774e1b31c Phase out slice for dense matrices (#2259)
* better documentation, test against eigen slicing

* remove a bunch of slices

* clean up templates; static asserts on vector types

* final purges of slice

* fix templates in debug and ears test

* fix slice mask bug

* fix slice bug

* boo. try to get around windows poor template deduction

* annoying left over bad windows ❄️ template
2023-09-01 11:11:46 -04:00
Alec Jacobson f5702f63e7 Fully avoid conflicting template parameters in AABB/signed_distance (#2257) [ci skip]
* readPLY: dont touch unread; point_mesh... dim pattern

* static asserts in pseudonormal test

* better handling of dimensions in signed_distance

* test fixed column case
2023-08-30 10:50:12 -04:00
Alec Jacobson 0262ef5866 Merge branch 'main' of github.com:libigl/libigl 2023-08-29 23:43:49 -04:00
Alec Jacobson 9350803420 fix namespace / include issues 2023-08-29 23:43:42 -04:00
Alec Jacobson 0e39b473b1 readPLY: dont touch unread; point_mesh... dim pattern (#2256) [ci skip] 2023-08-29 21:17:20 -04:00
Alec Jacobson 7a84503c8e Expose cutoff parameter for CGAL intersections; better default (#2255) [ci skip]
* cutoff in cgal intersections

* missing cast
2023-08-28 22:12:19 -04:00
Alec Jacobson deae7a2767 unfix dimensions 2023-08-26 23:16:00 -04:00
Alec Jacobson a0bb5bb813 fix dimensions 2023-08-26 23:13:36 -04:00
Alec Jacobson 5779714a5b fix hardcoded vectorxi 2023-08-26 23:01:47 -04:00
Alec Jacobson 687530283c Fix a bunch of warnings (#2254)
* fix a couple warnings

* fix a bunch of warnings (mostly unused variable)

* fix a bunch of warnings and simplify params

* Special assert so that variables aren't seen as unused

* fix tutorial

* undo erroneous line removal

* ASSERT -> IGL_ASSERT

* VSC ❄️ doesn't realize MAX_DEPTH is conts
2023-08-26 22:42:47 -04:00
Alec Jacobson 5c17f85621 fix debug compile bug 2023-08-25 10:56:39 -04:00
Alec Jacobson e5e0539e7d Remove extra calls to set_face_based (#2253) 2023-08-25 10:40:33 -04:00
Alec Jacobson eee808949e info about header/static [ci skip] 2023-08-24 17:57:59 -04:00
Alec Jacobson 75209c5d6c Robust isolines (#2251)
* robust isolines, test

* documentation
2023-08-24 17:24:17 -04:00
Alec Jacobson ab6229c77a Euler Characteristic tests (#2250)
* test for euler characteristic

* doc
2023-08-23 16:19:42 -04:00
Alec Jacobson b1fe6ba49c read blank lines as comments (#2247) [ci skip] 2023-08-22 20:20:53 -04:00
Alec Jacobson 8d940367bf support rowmajor (#2246) [ci skip] 2023-08-22 20:20:34 -04:00
Alec Jacobson fb13b11a19 border vertex for quads (#2245) [ci skip] 2023-08-22 15:32:43 -04:00
Alec Jacobson 7c58cb041d better doc; [ci skip] 2023-08-22 14:32:54 -04:00
Alec Jacobson 10e95bb93b robust ray box intersect (#2244) [ci skip]
* nan-proof min/max

* templates
2023-08-22 14:28:34 -04:00
Alec Jacobson 00100b60db bad assert [ci skip] 2023-08-22 14:06:19 -04:00
Alec Jacobson 3f8c5426b8 further split up mqwf templates 2023-08-22 12:20:19 -04:00
Alec Jacobson fd16e24391 assertion bug and too large allocation 2023-08-21 21:33:04 -04:00
Alec Jacobson 44785345e5 float templates + fix (#2243) [ci skip] 2023-08-21 21:09:24 -04:00
Alec Jacobson 71676a111e Remove omp pragmas (#2242) [ci skip]
* remove omp pragmas

* continue -> return
2023-08-21 17:54:51 -04:00
Alec Jacobson e5e7d8a76a fix 2025 with documentation [ci skip] 2023-08-21 17:47:15 -04:00
Alec Jacobson 10002b6cf1 block windows from gl version hell 2023-08-21 17:03:11 -04:00
Alec Jacobson 418dd43cfe small changes for python to compile (#2241) 2023-08-21 11:19:20 -04:00
Alec Jacobson 9162fb7d79 Fix 2228 with blas check on linux (#2240)
* split up 406; cmake

* split up 716

* rm old file

* 716 changes to main

* 709 split up

* missing include

* special syntax for windows ❄️

* stupid windows struct/class

* split up 805

* split up 610)'

* Fix 2228 with blas check on linux
2023-08-20 16:49:05 -04:00
hanxiaoandAlec Jacobson dd38f82afd Ear clipping function fix (#1565) [ci skip]
* fix the is_ear check

* fix order of outputs; overload that does any orientation

---------

Co-authored-by: Alec Jacobson <alecjacobson@gmail.com>
2023-08-19 23:05:58 -04:00
215368a07b Speed up of SelfIntersectMesh: (#1413) [ci skip
* Speed up of SelfIntersectMesh:
The test for intersection of two triangles sharing a common edge
has been optimized to reject non-overlaping triangles with
the least amount of

* Update SelfIntersectMesh.h

---------

Co-authored-by: Jérémie Dumas <jdumas@users.noreply.github.com>
Co-authored-by: Alec Jacobson <alecjacobson@gmail.com>
2023-08-19 20:43:44 -04:00
Sven-Kristofer PilzandAlec Jacobson 17787c86d6 Reduce dynamic allocations for AABB queries (#2001) [ci skip]
* Use static num of cols if available.

* Don't allocate a new vector for only one triangle.

* bug in test

---------

Co-authored-by: Alec Jacobson <alecjacobson@gmail.com>
2023-08-19 20:42:46 -04:00
Alec Jacobson f3f7879364 Split up larger tutorials (#2237) [ci skip]
* split up 406; cmake

* split up 716

* rm old file

* 716 changes to main

* 709 split up

* missing include

* special syntax for windows ❄️

* stupid windows struct/class

* split up 805

* split up 610)'
2023-08-19 19:19:44 -04:00
Alec Jacobson e2a345a43d Alecjacobson/fix mqwf ldlt (#2239)
* enable ldlt

* mqwf test
2023-08-19 17:34:59 -04:00
Alec Jacobson e45a7e0868 missing PI on windows ❄️ 2023-08-19 12:00:29 -04:00
Alec Jacobson c410e80608 turning number in 2D 2023-08-19 11:51:41 -04:00
Alec Jacobson 7765697eb6 split windows header-only tutorial actions (#2238)
* split windows header-only tutorial actions

* double quote issue?

* split 7 into 8 and 9
2023-08-19 11:06:48 -04:00
Alec Jacobson 83922780e1 Missing colon in CMakeLists.txt
Not sure how this was ever working.
2023-08-18 20:42:31 -04:00
Vladimir S. FONOVandAlec Jacobson 02e0a1ba83 Separated png module from opengl, added unit test for png (#1693) [ci skip]
* ENH: separate png from opengl, by splitting it into stb and opengl_image modules
     Added a unit test for PNG,BMP,TGA,JPG reading and writing
     Renamed module png to stb
     Renamed functions readPNG to read_image and writePNG to write_image

* name folder by dependency; consistent arg order

---------

Co-authored-by: Alec Jacobson <alecjacobson@gmail.com>
2023-08-18 14:32:25 -04:00
Alexander Sulfrian 97fb89c955 Source code should not be marked as executable (#2231) [ci skip]
The executable file flag should only be used for binaries and scripts
with a shebang specifying the interpreter of the script.
2023-08-18 11:04:36 -04:00
62fe771ae1 Fix blue_noise and random_points_on_mesh reproducibility (#2235)
* Fix `blue_noise` and `random_points_on_mesh` reproducibility

- added new overload for `blue_noise` and `random_points_on_mesh` for that accept an UnformRandomBitGenerator as input. The default signature (ie without URBG) still works, and uses by default std::minstd_rand initialized with random seed generated by std::rand(). This is following the existing behaviour of `randperm`.
- added reproducibility test case for `blue_noise` and `random_points_on_mesh`

* `blue_noise` and `random_points_on_mesh` overloads without an URBG parameter now use a fixed default seed

ie `std::minstd_rand()`

default seed

* Fix static compilation of tutorials

* revert to jdumas std::rand seed for default

* missing templates on linux

* more missing linux templates

* use std names rather than expansions in explicit templates

---------

Co-authored-by: stourneux <stourneux@buf.com>
Co-authored-by: seb-tourneux <sebastientourneux1@gmail.com>
2023-08-17 23:43:54 -04:00
a183e28109 Fix scale and reflections in Procrustes solver (#2226) [ci skip]
* Allow returning reflections from polar_dec and polar_svd

* Fix scale in Procrustes solver

* Fix reflection case in Procrustes solver

* Add unit test for Procrustes

* fix overloads for backwards comp

* missing templates on linux

---------

Co-authored-by: Alec Jacobson <alecjacobson@adobe.com>
Co-authored-by: Alec Jacobson <alecjacobson@gmail.com>
2023-08-17 22:10:23 -04:00
a69c8c96f3 Adjust igl::boundary_conditions(...) to support 3D cages (#2229)
* Calculate boundary conditions for cage faces

* Remove std:: prefix to conform to original libigl

* Adjust tests to new boundary_conditions(...)

* Adjusting tutorial 403 to new boundary_conditions(...)

* Removing unnecessary include

* Remove tolerances from boundary conditions for cages to prevent dups

---------

Co-authored-by: Daniel <daniel.stoeter@gris.tu-darmstadt.de>
Co-authored-by: Alec Jacobson <alecjacobson@gmail.com>
2023-08-17 19:18:42 -04:00
Alec Jacobson 724ff6b05a Remove deprecated functions (#2234)
* basic config file

* documentation for two funcs

* better theme; subnamespace

* A-c

* documentation for all core headers

* more documentation

* documentation for all headers (except a few classes)

* rm accidental comment on igl

* just h

* typo

* accidental delete

* fix compile issues

* add main page [ci skip]

* relative include paths

* relative include paths

* inexplicably need two more templates

* rm get_seconds_hires

* make fwn namespace private for dox

* hide internal fwn from documentation

* fix doc

* rm deprecated euler

* rm __1
2023-08-17 00:47:43 -04:00
Nico 3cf08b7f68 Cleanup #2216 (#2225) 2023-08-16 21:13:27 -04:00
Alec Jacobson 5ded7da086 Update README.md [ci skip] 2023-08-16 13:15:48 -04:00
Alec Jacobson 2cc372f70d Doxygen based documentation (#2233)
* basic config file

* documentation for two funcs

* better theme; subnamespace

* A-c

* documentation for all core headers

* more documentation

* documentation for all headers (except a few classes)

* rm accidental comment on igl

* just h

* typo

* accidental delete

* fix compile issues

* add main page [ci skip]
2023-08-16 13:14:06 -04:00
Alec Jacobson b1bd5b1216 spectra module (#2216)
* lscm hessian and spectral

* spectra module + test

* try to use Eigen3_FOUND (not working locally)

* use fork

* Don't use size_t for small int (windows hell)
2023-06-28 11:37:34 -04:00
Alec Jacobson 598b0b194a lscm hessian and spectral (#2214) [ci skip] 2023-06-28 11:35:55 -04:00
Alec Jacobson 4de0a0569a use vector () (#2218) [ci skip] 2023-06-28 11:35:36 -04:00
Fabien Péan afafc7cf5a Fix libigl-config.cmake.in (#2188) 2023-06-26 11:45:34 -04:00
Chao Li 514271af51 Implement full type mass matrix (#2193) 2023-06-26 10:47:59 -04:00
Alec Jacobson 282388c68a switch to gmp mirror (#2215)
* switch to gmp mirror

* use gist for patch
2023-06-25 10:14:36 -04:00
Felix Wang 7b6cc27284 Add missing <cstdint> header for gcc 13 (#2192) 2023-04-20 15:42:48 -04:00
Q-MinhandAlec Jacobson a05865e265 Fix ambiguous assignment operator compile error (#2157) [ci skip]
* Fix ambiguous assignment operator compile error

* Revert "Fix ambiguous assignment operator compile error"

This reverts commit 661c482140.

* Fix ambiguous assignment operator compile error

* Add typename

* add template (hopefully trigger error on windows CI

* simpler fix for windows

* use DerivedFI

---------

Co-authored-by: Alec Jacobson <alecjacobson@adobe.com>
2023-03-15 09:26:34 -04:00
Vladimir S. FONOV 1d007f4252 Fast mesh-to-mesh intersection and mesh self intersection without CGAL (#2109)
* Added code for fast triangle-triangle intersection checking and function for fast detection of mesh self-intersections and mesh-to-mesh intersections withoug CGAL

* Fixed auto parameters in lambda helper function

* Replaced cbegin/cend with begin/end

* Fixed auto parameters in lambda helper function

* Added tests for igl::tri_tri_intersection_test_3d

* Added more tests, converted macros in Guigue2003_tri_tri_intersect.cpp to proper c++

* Renamed files and function names to follow IGL guidelines,
added reference to the original license for tri_tri_intersect
2023-03-14 11:37:22 -04:00
Alec Jacobson 3374c1ad71 Update ViewerData.cpp (#2173) [ci skip] 2023-02-25 12:27:17 -05:00
Alec Jacobson 90464ffbc3 Fixes 2174 [ci skip]
Fixes 2174
2023-02-21 08:19:09 -05:00
Alec Jacobson 7e5512ce71 try to use j2 on windows (#2170) 2023-02-11 23:58:58 -05:00
Alec Jacobson 46f0860c18 fix unique_rows and sortrows templating (#2169) 2023-02-11 18:48:39 -05:00
Alec Jacobson 67b406d60d Merge branch 'main' of github.com:libigl/libigl [ci skip] 2023-02-11 14:03:24 -05:00
Alec Jacobson c01718d0b4 fix marker documentation [ci skip] 2023-02-11 14:02:50 -05:00
Alec Jacobson 78015d4da1 bump mpfr version; add logic for mac os cross compiling (#2165)
* bump mpfr version; add logic for mac os cross compiling

* hmm github actions cmake complains where my didn't

* split up tests and tutorial in header only CI

* hmmm why isn't matrix working

* try to fix matrix a different way

* better names

* oops wrong tests in name

* typpppoooo

* mooooree typpppoooos
2023-02-11 00:42:25 -05:00
1370 changed files with 49224 additions and 31783 deletions
+20
View File
@@ -0,0 +1,20 @@
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
*.tex text
*.bib text
*.svg text
*.py text
*.vbs text
*.cpp text
*.hpp text
Makefile text
# Declare files that will always have CRLF line endings on checkout.
*.sln text eol=crlf
# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary
+52 -18
View File
@@ -20,19 +20,14 @@ jobs:
####################
Unix:
name: ${{ matrix.name }} (${{ matrix.config }}, ${{ fromJSON('["HeaderOnly", "Static"]')[matrix.static == 'ON'] }})
name: ${{ matrix.os }} ${{ fromJSON('["Header-Only", "Static"]')[matrix.build-params.static == 'ON'] }} ${{ matrix.build-params.tutorials == 'ON' && 'tutorial' || ''}} ${{ matrix.build-params.tests == 'ON' && 'tests' || ''}} ${{ matrix.config }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, macos-latest]
os: [ubuntu-24.04, macos-latest]
config: [Release]
static: [ON, OFF]
include:
- os: macos-latest
name: macOS
- os: ubuntu-20.04
name: Linux
build-params: [ {static: ON, tutorials: ON, tests: ON }, {static: OFF, tutorials: OFF, tests: ON }, {static: OFF, tutorials: ON, tests: OFF }]
env:
IGL_NUM_THREADS: 1 # See https://github.com/libigl/libigl/pull/996
steps:
@@ -57,12 +52,18 @@ jobs:
run: |
HOMEBREW_NO_AUTO_UPDATE=1 brew install ccache
- name: Setup Xcode version
if: runner.os == 'macOS'
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '16.3.0'
- name: Cache Build
id: cache-build
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: ~/.ccache
key: ${{ runner.os }}-${{ matrix.config }}-${{ matrix.static }}-cache
key: ${{ runner.os }}-${{ matrix.config }}-${{ matrix.build-params.static }}-cache
- name: Prepare ccache
run: |
@@ -73,30 +74,48 @@ jobs:
run: |
mkdir -p build
cd build
# https://github.com/eclipse-ecal/ecal/issues/2041
cmake .. \
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_BUILD_TYPE=${{ matrix.config }} \
-DLIBIGL_USE_STATIC_LIBRARY=${{ matrix.static }} \
-DLIBIGL_USE_STATIC_LIBRARY=${{ matrix.build-params.static }} \
-DLIBIGL_BUILD_TUTORIALS=${{ matrix.build-params.tutorials }} \
-DLIBIGL_GLFW_TESTS=OFF \
-DLIBIGL_BUILD_TESTS=${{ matrix.build-params.tests }} \
-DLIBIGL_COPYLEFT_CGAL=ON
- name: Build
run: cd build; make -j2; ccache --show-stats
- name: Tests
run: cd build; ctest --verbose
run: cd build; ctest --show-only; ctest --verbose
####################
# Windows
####################
Windows:
name: Windows (${{ matrix.config }}, ${{ fromJSON('["HeaderOnly", "Static"]')[matrix.static == 'ON'] }})
name: Windows ${{ fromJSON('["Header-Only", "Static"]')[matrix.build-params.static == 'ON'] }} ${{ matrix.build-params.tutorials == 'ON' && 'tutorial' || ''}} ${{ matrix.build-params.selected_tutorial != 'NONE' && matrix.build-params.selected_tutorial || '' }} ${{ matrix.build-params.tests == 'ON' && 'tests' || ''}} ${{ matrix.config }}
runs-on: windows-2022
strategy:
fail-fast: false
matrix:
config: [Release]
static: [ON, OFF]
build-params: [
{static: ON, tutorials: ON, tests: ON, selected_tutorial: NONE},
{static: OFF, tutorials: OFF, tests: ON, selected_tutorial: NONE},
{static: OFF, tutorials: ON, tests: OFF, selected_tutorial: 1},
{static: OFF, tutorials: ON, tests: OFF, selected_tutorial: 2},
{static: OFF, tutorials: ON, tests: OFF, selected_tutorial: 3},
{static: OFF, tutorials: ON, tests: OFF, selected_tutorial: 4},
{static: OFF, tutorials: ON, tests: OFF, selected_tutorial: 5},
{static: OFF, tutorials: ON, tests: OFF, selected_tutorial: 6},
{static: OFF, tutorials: ON, tests: OFF, selected_tutorial: 7},
{static: OFF, tutorials: ON, tests: OFF, selected_tutorial: 8},
{static: OFF, tutorials: ON, tests: OFF, selected_tutorial: 9},
{static: OFF, tutorials: ON, tests: OFF, selected_tutorial: 10},
]
steps:
- name: Checkout repository
uses: actions/checkout@v1
@@ -112,10 +131,10 @@ jobs:
- name: Cache build
id: cache-build
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: ${{ env.appdata }}\Mozilla\sccache
key: ${{ runner.os }}-${{ matrix.config }}-${{ matrix.static }}-cache
key: ${{ runner.os }}-${{ matrix.config }}-${{ matrix.build-params.static }}-cache
- name: Prepare sccache
run: |
@@ -129,15 +148,30 @@ jobs:
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=x64
# https://github.com/eclipse-ecal/ecal/issues/2041
cmake -G Ninja ^
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 ^
-DCMAKE_CXX_COMPILER_LAUNCHER=sccache ^
-DCMAKE_BUILD_TYPE=${{ matrix.config }} ^
-DLIBIGL_USE_STATIC_LIBRARY=${{ matrix.static }} ^
-DLIBIGL_USE_STATIC_LIBRARY=${{ matrix.build-params.static }} ^
-DLIBIGL_COPYLEFT_CGAL=ON ^
-DLIBIGL_BUILD_TUTORIALS=${{ matrix.build-params.tutorials }} ^
-DLIBIGL_BUILD_TESTS=${{ matrix.build-params.tests }} ^
-DLIBIGL_GLFW_TESTS=OFF ^
-DLIBIGL_TUTORIALS_CHAPTER1=${{ (matrix.build-params.selected_tutorial == 'NONE' || matrix.build-params.selected_tutorial == '1') && 'ON' || 'OFF' }} ^
-DLIBIGL_TUTORIALS_CHAPTER2=${{ (matrix.build-params.selected_tutorial == 'NONE' || matrix.build-params.selected_tutorial == '2') && 'ON' || 'OFF' }} ^
-DLIBIGL_TUTORIALS_CHAPTER3=${{ (matrix.build-params.selected_tutorial == 'NONE' || matrix.build-params.selected_tutorial == '3') && 'ON' || 'OFF' }} ^
-DLIBIGL_TUTORIALS_CHAPTER4=${{ (matrix.build-params.selected_tutorial == 'NONE' || matrix.build-params.selected_tutorial == '4') && 'ON' || 'OFF' }} ^
-DLIBIGL_TUTORIALS_CHAPTER5=${{ (matrix.build-params.selected_tutorial == 'NONE' || matrix.build-params.selected_tutorial == '5') && 'ON' || 'OFF' }} ^
-DLIBIGL_TUTORIALS_CHAPTER6=${{ (matrix.build-params.selected_tutorial == 'NONE' || matrix.build-params.selected_tutorial == '6') && 'ON' || 'OFF' }} ^
-DLIBIGL_TUTORIALS_CHAPTER7=${{ (matrix.build-params.selected_tutorial == 'NONE' || matrix.build-params.selected_tutorial == '7') && 'ON' || 'OFF' }} ^
-DLIBIGL_TUTORIALS_CHAPTER8=${{ (matrix.build-params.selected_tutorial == 'NONE' || matrix.build-params.selected_tutorial == '8') && 'ON' || 'OFF' }} ^
-DLIBIGL_TUTORIALS_CHAPTER9=${{ (matrix.build-params.selected_tutorial == 'NONE' || matrix.build-params.selected_tutorial == '9') && 'ON' || 'OFF' }} ^
-DLIBIGL_TUTORIALS_CHAPTER10=${{ (matrix.build-params.selected_tutorial == 'NONE' || matrix.build-params.selected_tutorial == '10') && 'ON' || 'OFF' }} ^
-B build ^
-S .
cmake --build build -j2
- name: Tests
run: cd build; ctest --verbose -j2
run: cd build; ctest --show-only; ctest --verbose -j2
+4
View File
@@ -47,3 +47,7 @@ LibiglOptions.cmake
# macos debris
.DS_Store
*~
dox/
latex/
scripts/
+23 -2
View File
@@ -6,6 +6,8 @@ else()
set(LIBIGL_TOPLEVEL_PROJECT OFF)
endif()
# Check required CMake version
set(REQUIRED_CMAKE_VERSION "3.16.0")
if(LIBIGL_TOPLEVEL_PROJECT)
@@ -35,7 +37,7 @@ if(HUNTER_ENABLED)
endif()
################################################################################
project(libigl VERSION 2.4.0)
project(libigl VERSION 2.5.0)
# CMake module path
list(PREPEND CMAKE_MODULE_PATH
@@ -55,6 +57,8 @@ set_property(GLOBAL PROPERTY __igl_module_path ${CMAKE_MODULE_PATH})
set(LIBIGL_DEFAULT_CGAL ${LIBIGL_TOPLEVEL_PROJECT})
set(MATLAB_ADDITIONAL_VERSIONS
"R2023b=10.4"
"R2023a=10.4"
"R2022b=10.3"
"R2022a=10.2"
"R2021b=10.1"
@@ -74,6 +78,14 @@ if(LIBIGL_TOPLEVEL_PROJECT)
message(WARNING "Mosek not found, disabling igl_restricted::mosek module.")
endif()
endif()
set(LIBIGL_DEFAULT_COMISO ${LIBIGL_TOPLEVEL_PROJECT})
if(LIBIGL_TOPLEVEL_PROJECT AND (NOT APPLE) AND UNIX)
find_package(BLAS QUIET)
if(NOT BLAS_FOUND)
set(LIBIGL_DEFAULT_COMISO OFF)
message(WARNING "BLAS not found, disabling igl_copyleft::comiso module.")
endif()
endif()
# Build tests and tutorials
option(LIBIGL_BUILD_TESTS "Build libigl unit test" ${LIBIGL_TOPLEVEL_PROJECT})
@@ -87,12 +99,14 @@ option(LIBIGL_USE_STATIC_LIBRARY "Use libigl as static library" ${LIBIGL_TOPLEVE
# Permissive modules. These modules are available under MPL2 license, and their dependencies are available
# under a permissive or public domain license.
option(LIBIGL_CYCODEBASE "Build target igl::cycodebase" ${LIBIGL_TOPLEVEL_PROJECT})
option(LIBIGL_EMBREE "Build target igl::embree" ${LIBIGL_TOPLEVEL_PROJECT})
option(LIBIGL_GLFW "Build target igl::glfw" ${LIBIGL_TOPLEVEL_PROJECT})
option(LIBIGL_IMGUI "Build target igl::imgui" ${LIBIGL_TOPLEVEL_PROJECT})
option(LIBIGL_OPENGL "Build target igl::opengl" ${LIBIGL_TOPLEVEL_PROJECT})
option(LIBIGL_PNG "Build target igl::png" ${LIBIGL_TOPLEVEL_PROJECT})
option(LIBIGL_STB "Build target igl::stb" ${LIBIGL_TOPLEVEL_PROJECT})
option(LIBIGL_PREDICATES "Build target igl::predicates" ${LIBIGL_TOPLEVEL_PROJECT})
option(LIBIGL_SPECTRA "Build target igl::spectra" ${LIBIGL_TOPLEVEL_PROJECT})
option(LIBIGL_XML "Build target igl::xml" ${LIBIGL_TOPLEVEL_PROJECT})
# Copyleft modules. These modules are available under GPL license, and their dependencies are
@@ -108,6 +122,12 @@ option(LIBIGL_RESTRICTED_MATLAB "Build target igl_restricted::matlab" ${LIBI
option(LIBIGL_RESTRICTED_MOSEK "Build target igl_restricted::mosek" ${LIBIGL_DEFAULT_MOSEK})
option(LIBIGL_RESTRICTED_TRIANGLE "Build target igl_restricted::triangle" ${LIBIGL_TOPLEVEL_PROJECT})
# GLFW doesn't run on headless CI machines so don't run (or build them).
# Unfortunately on headless mac machines glfw seems to hang rather than crash
# making it hard to catch at runtime.
option(LIBIGL_GLFW_TESTS "Build igl::glfw tests" ${LIBIGL_TOPLEVEL_PROJECT})
option(LIBIGL_WARNINGS_AS_ERRORS "Turn on many warnings and treat as errors" OFF)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
@@ -167,3 +187,4 @@ if(LIBIGL_INSTALL)
write_basic_package_version_file("${version_config_file}" COMPATIBILITY SameMajorVersion)
install(FILES "${project_config_out}" "${version_config_file}" DESTINATION "${export_dest_dir}")
endif()
+1 -1
View File
@@ -56,7 +56,7 @@
# option(LIBIGL_GLFW "Build target igl::glfw" ON)
# option(LIBIGL_IMGUI "Build target igl::imgui" ON)
# option(LIBIGL_OPENGL "Build target igl::opengl" ON)
# option(LIBIGL_PNG "Build target igl::png" ON)
# option(LIBIGL_STB "Build target igl::stb" ON)
# option(LIBIGL_PREDICATES "Build target igl::predicates" ON)
# option(LIBIGL_XML "Build target igl::xml" ON)
# option(LIBIGL_COPYLEFT_CGAL "Build target igl_copyleft::cgal" ON)
+2 -2
View File
@@ -8,6 +8,6 @@
Documentation, tutorial, and instructions at <https://libigl.github.io>.
| 🚨 Important |
| 🆕 Doxygen Documentation |
|:---|
| The latest version of libigl (v2.4.0) introduces some **breaking changes** to its CMake build system. Please read our [changelog](https://libigl.github.io/changelog/) page for instructions on how to update your project accordingly. |
| The latest version of libigl (v2.5.0) introduces [doxygen generated detailed documentation](https://libigl.github.io/dox/index.html) |
-95
View File
@@ -1,95 +0,0 @@
# Try to find the GNU Multiple Precision Arithmetic Library (GMP)
# See http://gmplib.org/
if(${CMAKE_VERSION} VERSION_LESS "3.18.0")
set(REQUIRED_FLAG "")
else()
set(REQUIRED_FLAG REQUIRED)
endif()
# On Windows, we must use the pre-compiled versions downloaded with libigl
if(WIN32)
set(NO_DEFAULT_FLAG NO_DEFAULT_PATH)
else()
set(NO_DEFAULT_FLAG "")
endif()
find_path(GMP_INCLUDES
NAMES
gmp.h
PATHS
ENV GMP_DIR
${INCLUDE_INSTALL_DIR}
PATH_SUFFIXES
include
${REQUIRED_FLAG}
${NO_DEFAULT_FLAG}
)
find_library(GMP_LIBRARIES
NAMES
gmp
libgmp-10
PATHS
ENV GMP_DIR
${LIB_INSTALL_DIR}
PATH_SUFFIXES
lib
${REQUIRED_FLAG}
${NO_DEFAULT_FLAG}
)
set(GMP_EXTRA_VARS "")
if(WIN32)
# Find dll file and set IMPORTED_LOCATION to the .dll file
find_file(GMP_RUNTIME_LIB
NAMES
gmp.dll
libgmp-10.dll
PATHS
ENV GMP_DIR
${LIB_INSTALL_DIR}
PATH_SUFFIXES
lib
${REQUIRED_FLAG}
${NO_DEFAULT_FLAG}
)
list(APPEND GMP_EXTRA_VARS GMP_RUNTIME_LIB)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(GMP
REQUIRED_VARS
GMP_INCLUDES
GMP_LIBRARIES
${GMP_EXTRA_VARS}
REASON_FAILURE_MESSAGE
"GMP is not installed on your system. Either install GMP using your preferred package manager, or disable libigl modules that depend on GMP, such as CGAL. See LibiglOptions.cmake.sample for configuration options. Do not forget to delete your <build>/CMakeCache.txt for the changes to take effect."
)
mark_as_advanced(GMP_INCLUDES GMP_LIBRARIES)
if(GMP_INCLUDES AND GMP_LIBRARIES AND NOT TARGET gmp::gmp)
if(GMP_RUNTIME_LIB)
add_library(gmp::gmp SHARED IMPORTED)
else()
add_library(gmp::gmp UNKNOWN IMPORTED)
endif()
# Set public header location and link language
set_target_properties(gmp::gmp PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
INTERFACE_INCLUDE_DIRECTORIES "${GMP_INCLUDES}"
)
# Set lib location. On Windows we specify both the .lib and the .dll paths
if(GMP_RUNTIME_LIB)
set_target_properties(gmp::gmp PROPERTIES
IMPORTED_IMPLIB "${GMP_LIBRARIES}"
IMPORTED_LOCATION "${GMP_RUNTIME_LIB}"
)
else()
set_target_properties(gmp::gmp PROPERTIES
IMPORTED_LOCATION "${GMP_LIBRARIES}"
)
endif()
endif()
-95
View File
@@ -1,95 +0,0 @@
# Try to find the MPFR library
# See http://www.mpfr.org/
if(${CMAKE_VERSION} VERSION_LESS "3.18.0")
set(REQUIRED_FLAG "")
else()
set(REQUIRED_FLAG REQUIRED)
endif()
# On Windows, we must use the pre-compiled versions downloaded with libigl
if(WIN32)
set(NO_DEFAULT_FLAG NO_DEFAULT_PATH)
else()
set(NO_DEFAULT_FLAG "")
endif()
find_path(MPFR_INCLUDES
NAMES
mpfr.h
PATHS
ENV MPFR_DIR
${INCLUDE_INSTALL_DIR}
PATH_SUFFIXES
include
${REQUIRED_FLAG}
${NO_DEFAULT_FLAG}
)
find_library(MPFR_LIBRARIES
NAMES
mpfr
libmpfr-4
PATHS
ENV MPFR_DIR
${LIB_INSTALL_DIR}
PATH_SUFFIXES
lib
${REQUIRED_FLAG}
${NO_DEFAULT_FLAG}
)
set(MPFR_EXTRA_VARS "")
if(WIN32)
# Find dll file and set IMPORTED_LOCATION to the .dll file
find_file(MPFR_RUNTIME_LIB
NAMES
mpfr.dll
libmpfr-4.dll
PATHS
ENV MPFR_DIR
${LIB_INSTALL_DIR}
PATH_SUFFIXES
lib
${REQUIRED_FLAG}
${NO_DEFAULT_FLAG}
)
list(APPEND MPFR_EXTRA_VARS MPFR_RUNTIME_LIB)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(MPFR
REQUIRED_VARS
MPFR_INCLUDES
MPFR_LIBRARIES
${MPFR_EXTRA_VARS}
REASON_FAILURE_MESSAGE
"MPFR is not installed on your system. Either install MPFR using your preferred package manager, or disable libigl modules that depend on MPFR, such as CGAL. See LibiglOptions.cmake.sample for configuration options. Do not forget to delete your <build>/CMakeCache.txt for the changes to take effect."
)
mark_as_advanced(MPFR_INCLUDES MPFR_LIBRARIES)
if(MPFR_INCLUDES AND MPFR_LIBRARIES AND NOT TARGET mpfr::mpfr)
if(MPFR_RUNTIME_LIB)
add_library(mpfr::mpfr SHARED IMPORTED)
else()
add_library(mpfr::mpfr UNKNOWN IMPORTED)
endif()
# Set public header location and link language
set_target_properties(mpfr::mpfr PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
INTERFACE_INCLUDE_DIRECTORIES "${MPFR_INCLUDES}"
)
# Set lib location. On Windows we specify both the .lib and the .dll paths
if(MPFR_RUNTIME_LIB)
set_target_properties(mpfr::mpfr PROPERTIES
IMPORTED_IMPLIB "${MPFR_LIBRARIES}"
IMPORTED_LOCATION "${MPFR_RUNTIME_LIB}"
)
else()
set_target_properties(mpfr::mpfr PROPERTIES
IMPORTED_LOCATION "${MPFR_LIBRARIES}"
)
endif()
endif()
+7 -2
View File
@@ -33,8 +33,12 @@ function(igl_add_library module_name)
target_compile_definitions(${module_name} ${IGL_SCOPE} -DIGL_STATIC_LIBRARY)
endif()
# C++11 features
target_compile_features(${module_name} ${IGL_SCOPE} cxx_std_11)
# C++17 features
target_compile_features(${module_name} ${IGL_SCOPE} cxx_std_17)
if(LIBIGL_WARNINGS_AS_ERRORS)
target_compile_options(${module_name} PRIVATE -Wall -Wextra -Wpedantic -Wno-sign-compare -Werror -Wno-gnu -Wno-unknown-pragmas)
endif()
# Other compilation flags
if(MSVC)
@@ -42,6 +46,7 @@ function(igl_add_library module_name)
target_compile_options(${module_name} ${IGL_SCOPE} $<$<COMPILE_LANGUAGE:CXX>:/MP> $<$<COMPILE_LANGUAGE:CXX>:/bigobj>)
target_compile_definitions(${module_name} ${IGL_SCOPE} -DNOMINMAX)
# Silencing some compilation warnings
if(LIBIGL_USE_STATIC_LIBRARY)
target_compile_options(${module_name} PRIVATE
+12 -1
View File
@@ -7,7 +7,9 @@ function(igl_add_tutorial name)
endforeach()
message(STATUS "Creating libigl tutorial: ${name}")
add_executable(${name} ${CMAKE_CURRENT_SOURCE_DIR}/${name}/main.cpp)
# get all cpp files in ${CMAKE_CURRENT_SOURCE_DIR}/${name}/
file(GLOB SRCFILES ${CMAKE_CURRENT_SOURCE_DIR}/${name}/*.cpp)
add_executable(${name} ${SRCFILES})
target_link_libraries(${name} PRIVATE
igl::core
igl::tutorial_data
@@ -15,4 +17,13 @@ function(igl_add_tutorial name)
)
set_target_properties(${name} PROPERTIES FOLDER Libigl_Tutorials)
# Do this codesign only on macOS
# add_custom_command(TARGET your_target POST_BUILD COMMAND codesign -s - $<TARGET_FILE:your_target>
if(APPLE)
add_custom_command(TARGET ${name} POST_BUILD
COMMAND codesign -f -s - $<TARGET_FILE:${name}>
COMMENT "Codesigning ${name}"
)
endif()
endfunction()
+4
View File
@@ -50,6 +50,10 @@ function(igl_copy_dll target)
if(NOT WIN32)
return()
endif()
if(NOT TARGET ${target})
message(STATUS "igl_copy_dll() was called with a non-target: ${target}")
return()
endif()
# Sanity checks
get_target_property(TYPE ${target} TYPE)
+4
View File
@@ -1,3 +1,7 @@
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
find_dependency(Eigen3 REQUIRED)
find_dependency(Threads REQUIRED)
include("${CMAKE_CURRENT_LIST_DIR}/LibiglConfigTargets.cmake")
check_required_components(Libigl)
-27
View File
@@ -1,27 +0,0 @@
# 1. Define module
igl_add_library(igl_copyleft_comiso)
# 2. Include headers
include(GNUInstallDirs)
target_include_directories(igl_copyleft_comiso ${IGL_SCOPE}
$<BUILD_INTERFACE:${libigl_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
# 3. Target sources
file(GLOB INC_FILES "${libigl_SOURCE_DIR}/include/igl/copyleft/comiso/*.h")
file(GLOB SRC_FILES "${libigl_SOURCE_DIR}/include/igl/copyleft/comiso/*.cpp")
igl_target_sources(igl_copyleft_comiso ${INC_FILES} ${SRC_FILES})
# 4. Dependencies
include(comiso)
igl_include(copyleft core)
target_link_libraries(igl_copyleft_comiso ${IGL_SCOPE}
igl::core
igl_copyleft::core
CoMISo::CoMISo
)
# 5. Unit tests
file(GLOB SRC_FILES "${libigl_SOURCE_DIR}/tests/include/igl/copyleft/comiso/*.cpp")
igl_add_test(igl_copyleft_comiso ${SRC_FILES})
+26
View File
@@ -0,0 +1,26 @@
# 1. Define module
igl_add_library(igl_cycodebase)
# 2. Include headers
include(GNUInstallDirs)
target_include_directories(igl_cycodebase ${IGL_SCOPE}
$<BUILD_INTERFACE:${libigl_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
# 3. Target sources
file(GLOB INC_FILES "${libigl_SOURCE_DIR}/include/igl/cycodebase/*.h")
file(GLOB SRC_FILES "${libigl_SOURCE_DIR}/include/igl/cycodebase/*.cpp")
igl_target_sources(igl_cycodebase ${INC_FILES} ${SRC_FILES})
# 4. Dependencies
include(cycodebase)
target_link_libraries(igl_cycodebase ${IGL_SCOPE}
igl::core
cyCodeBase::cyCodeBase
)
# 5. Unit tests
file(GLOB SRC_FILES "${libigl_SOURCE_DIR}/tests/include/igl/cycodebase/*.cpp")
igl_add_test(igl_cycodebase ${SRC_FILES})
+6
View File
@@ -21,3 +21,9 @@ target_link_libraries(igl_glfw ${IGL_SCOPE}
igl::opengl
glfw::glfw
)
# 5. Unit tests
if(LIBIGL_GLFW_TESTS)
file(GLOB SRC_FILES "${libigl_SOURCE_DIR}/tests/include/igl/opengl/glfw/*.cpp")
igl_add_test(igl_glfw ${SRC_FILES})
endif()
-23
View File
@@ -1,23 +0,0 @@
# 1. Define module
igl_add_library(igl_png)
# 2. Include headers
include(GNUInstallDirs)
target_include_directories(igl_png ${IGL_SCOPE}
$<BUILD_INTERFACE:${libigl_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
# 3. Target sources
file(GLOB INC_FILES "${libigl_SOURCE_DIR}/include/igl/png/*.h")
file(GLOB SRC_FILES "${libigl_SOURCE_DIR}/include/igl/png/*.cpp")
igl_target_sources(igl_png ${INC_FILES} ${SRC_FILES})
# 4. Dependencies
include(stb)
igl_include(opengl)
target_link_libraries(igl_png ${IGL_SCOPE}
igl::core
igl::opengl
stb::stb
)
+25
View File
@@ -0,0 +1,25 @@
# 1. Define module
igl_add_library(igl_spectra)
# 2. Include headers
include(GNUInstallDirs)
target_include_directories(igl_spectra ${IGL_SCOPE}
$<BUILD_INTERFACE:${libigl_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
# 3. Target sources
file(GLOB INC_FILES "${libigl_SOURCE_DIR}/include/igl/spectra/*.h")
file(GLOB SRC_FILES "${libigl_SOURCE_DIR}/include/igl/spectra/*.cpp")
igl_target_sources(igl_spectra ${INC_FILES} ${SRC_FILES})
# 4. Dependencies
include(spectra)
target_link_libraries(igl_spectra ${IGL_SCOPE}
igl::core
spectra::spectra
)
# 5. Unit tests
file(GLOB SRC_FILES "${libigl_SOURCE_DIR}/tests/include/igl/spectra/*.cpp")
igl_add_test(igl_spectra ${SRC_FILES})
+35
View File
@@ -0,0 +1,35 @@
# 1. Define module
igl_add_library(igl_stb)
# 2. Include headers
include(GNUInstallDirs)
target_include_directories(igl_stb ${IGL_SCOPE}
$<BUILD_INTERFACE:${libigl_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
# 3. Target sources
file(GLOB INC_FILES "${libigl_SOURCE_DIR}/include/igl/stb/*.h")
file(GLOB SRC_FILES "${libigl_SOURCE_DIR}/include/igl/stb/*.cpp")
if(LIBIGL_OPENGL)
message(STATUS "Including igl/opengl/stb support")
file(GLOB OPENGL_INC_FILES "${libigl_SOURCE_DIR}/include/igl/opengl/stb/*.h")
file(GLOB OPENGL_SRC_FILES "${libigl_SOURCE_DIR}/include/igl/opengl/stb/*.cpp")
list(APPEND INC_FILES ${OPENGL_INC_FILES})
list(APPEND SRC_FILES ${OPENGL_SRC_FILES})
endif()
igl_target_sources(igl_stb ${INC_FILES} ${SRC_FILES})
# 4. Dependencies
include(stb)
target_link_libraries(igl_stb ${IGL_SCOPE}
igl::core
stb::stb
)
if(LIBIGL_OPENGL)
igl_include(opengl)
target_link_libraries(igl_stb ${IGL_SCOPE}
igl::opengl
)
endif()
+3 -2
View File
@@ -13,18 +13,19 @@ include(igl_windows)
# Libigl permissive modules
igl_include(core)
igl_include_optional(cycodebase)
igl_include_optional(embree)
igl_include_optional(opengl)
igl_include_optional(glfw)
igl_include_optional(imgui)
igl_include_optional(predicates)
igl_include_optional(png)
igl_include_optional(stb)
igl_include_optional(spectra)
igl_include_optional(xml)
# Libigl copyleft modules
igl_include_optional(copyleft core)
igl_include_optional(copyleft cgal)
igl_include_optional(copyleft comiso)
igl_include_optional(copyleft tetgen)
# Libigl restricted modules
+22 -26
View File
@@ -4,32 +4,27 @@ endif()
message(STATUS "Third-party: creating targets 'Boost::boost'...")
cmake_minimum_required(VERSION 3.24) # Ensure modern FetchContent features
project(BoostFetchExample)
include(FetchContent)
# Define the Boost library to fetch
FetchContent_Declare(
boost-cmake
GIT_REPOSITORY https://github.com/Orphis/boost-cmake.git
GIT_TAG 7f97a08b64bd5d2e53e932ddf80c40544cf45edf
Boost
URL https://archives.boost.io/release/1.86.0/source/boost_1_86_0.tar.gz
URL_HASH MD5=ac857d73bb754b718a039830b07b9624
)
# Fetch Boost
FetchContent_MakeAvailable(Boost)
set(PREVIOUS_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
set(OLD_CMAKE_POSITION_INDEPENDENT_CODE ${CMAKE_POSITION_INDEPENDENT_CODE})
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# This guy will download boost using FetchContent
FetchContent_GetProperties(boost-cmake)
if(NOT boost-cmake_POPULATED)
FetchContent_Populate(boost-cmake)
# File lcid.cpp from Boost_locale.cpp doesn't compile on MSVC, so we exclude them from the default
# targets being built by the project (only targets explicitly used by other targets will be built).
add_subdirectory(${boost-cmake_SOURCE_DIR} ${boost-cmake_BINARY_DIR} EXCLUDE_FROM_ALL)
endif()
# Ensure Boost paths are set before CGAL
set(Boost_INCLUDE_DIR ${boost_SOURCE_DIR})
set(Boost_LIBRARY_DIR ${boost_BINARY_DIR})
set(CMAKE_POSITION_INDEPENDENT_CODE ${OLD_CMAKE_POSITION_INDEPENDENT_CODE})
set(CMAKE_CXX_FLAGS "${PREVIOUS_CMAKE_CXX_FLAGS}")
# Set VS target folders
set(boost_modules
# Add Boost libraries needed for your project
set(BOOST_LIBRARIES
container
regex
atomic
@@ -48,6 +43,7 @@ set(boost_modules
log_setup
unit_test_framework
math
multiprecision
program_options
timer
random
@@ -55,10 +51,10 @@ set(boost_modules
system
thread
type_erasure
)
foreach(module IN ITEMS ${boost_modules})
if(TARGET Boost_${module})
set_target_properties(Boost_${module} PROPERTIES FOLDER ThirdParty/Boost)
endif()
endforeach()
)
foreach(lib IN LISTS BOOST_LIBRARIES)
add_library(boost_${lib} INTERFACE)
target_include_directories(boost_${lib} INTERFACE ${Boost_SOURCE_DIR})
target_link_libraries(boost_${lib} INTERFACE Boost::${lib})
endforeach()
+6 -14
View File
@@ -7,8 +7,8 @@ message(STATUS "Third-party: creating target 'CGAL::CGAL'")
include(FetchContent)
FetchContent_Declare(
cgal
URL https://github.com/CGAL/cgal/releases/download/v5.4/CGAL-5.4-library.tar.xz
URL_MD5 996f7ee9ba1553edac60debb115699cd
URL https://github.com/CGAL/cgal/releases/download/v6.0.1/CGAL-6.0.1-library.tar.xz
URL_MD5 ea827f6778063e00554ae41f4c845492
)
FetchContent_GetProperties(cgal)
if(cgal_POPULATED)
@@ -29,29 +29,21 @@ function(cgal_import_target)
set(${NAME}_ROOT ${CMAKE_CURRENT_BINARY_DIR}/${NAME} CACHE PATH "")
endmacro()
include(gmp)
include(mpfr)
include(boost)
ignore_package(GMP 5.0.1)
set(GMP_INCLUDE_DIR ${gmp_INCLUDE_DIR})
set(GMP_LIBRARIES gmp::gmp)
set(GMPXX_INCLUDE_DIR ${GMP_INCLUDE_DIR})
set(GMPXX_LIBRARIES ${GMP_LIBRARIES})
ignore_package(MPFR 3.0.0)
set(MPFR_INCLUDE_DIR "")
set(MPFR_LIBRARIES mpfr::mpfr)
ignore_package(Boost 1.71.0)
set(Boost_INCLUDE_DIRS "")
set(Boost_LIBRARIES Boost::thread Boost::system)
set(Boost_LIBRARIES Boost::thread Boost::system Boost::multiprecision)
# Prefer Config mode before Module mode to prevent CGAL from loading its own FindXXX.cmake
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE)
# https://stackoverflow.com/a/71714947/148668
set(CGAL_DATA_DIR "unspecified")
set(CGAL_CMAKE_EXACT_NT_BACKEND "BOOST_BACKEND" CACHE STRING "CGAL exact NT backend")
set(CGAL_DISABLE_GMP ON CACHE BOOL "Disable GMP")
find_package(CGAL CONFIG COMPONENTS Core PATHS ${cgal_SOURCE_DIR} NO_DEFAULT_PATH)
endfunction()
-31
View File
@@ -1,31 +0,0 @@
if(TARGET CoMISo::CoMISo)
return()
endif()
message(STATUS "Third-party: creating target 'CoMISo::CoMISo'")
include(FetchContent)
FetchContent_Declare(
comiso
GIT_REPOSITORY https://github.com/libigl/CoMISo.git
GIT_TAG 536440e714f412e7ef6c0b96b90ba37b1531bb39
)
include(eigen)
FetchContent_MakeAvailable(comiso)
add_library(CoMISo::CoMISo ALIAS CoMISo)
# Copy .hh headers into a subfolder `CoMISo/`
file(GLOB_RECURSE INC_FILES "${comiso_SOURCE_DIR}/*.hh" "${comiso_SOURCE_DIR}/*.cc")
set(output_folder "${CMAKE_CURRENT_BINARY_DIR}/CoMISo/include/CoMISo")
message(VERBOSE "Copying CoMISo headers to '${output_folder}'")
foreach(filepath IN ITEMS ${INC_FILES})
file(RELATIVE_PATH filename "${comiso_SOURCE_DIR}" ${filepath})
configure_file(${filepath} "${output_folder}/${filename}" COPYONLY)
endforeach()
target_include_directories(CoMISo PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/CoMISo/include)
set_target_properties(CoMISo PROPERTIES FOLDER ThirdParty)
+18
View File
@@ -0,0 +1,18 @@
if(TARGET cycodebase::cycodebase)
return()
endif()
FetchContent_Declare(
cyCodeBase
GIT_REPOSITORY https://github.com/cemyuksel/cyCodeBase/
GIT_TAG e36f3cffca65eb12a8a071f0443128b7de6ed75d
)
FetchContent_Populate(cyCodeBase)
add_library(cyCodeBase_interface INTERFACE)
target_include_directories(cyCodeBase_interface INTERFACE ${cycodebase_SOURCE_DIR})
if(NOT (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64|i[3-6]86"))
target_compile_definitions(cyCodeBase_interface INTERFACE CY_NO_INTRIN_H)
endif()
add_library(cyCodeBase::cyCodeBase ALIAS cyCodeBase_interface)
+1 -1
View File
@@ -8,7 +8,7 @@ include(FetchContent)
FetchContent_Declare(
embree
GIT_REPOSITORY https://github.com/embree/embree.git
GIT_TAG v3.13.3
GIT_TAG v4.4.0
GIT_SHALLOW TRUE
)
+1 -1
View File
@@ -8,7 +8,7 @@ include(FetchContent)
FetchContent_Declare(
glad
GIT_REPOSITORY https://github.com/libigl/libigl-glad.git
GIT_TAG ceef55fcd08bdd16e985370a99cfb60e69623221
GIT_TAG 651a425101365aa6e8504988ef9bb363d066c5ee
)
FetchContent_MakeAvailable(glad)
-66
View File
@@ -1,66 +0,0 @@
if(TARGET gmp::gmp)
return()
endif()
# Download precompiled .dll on Windows
if(WIN32)
include(gmp_mpfr)
# Find_package will look for our downloaded lib on Windows, and system-wide on Linux/macOS
find_package(GMP REQUIRED)
else()
message(STATUS "Third-party: creating target 'gmp::gmp'")
include(FetchContent)
include(ProcessorCount)
ProcessorCount(Ncpu)
include(ExternalProject)
set(prefix ${FETCHCONTENT_BASE_DIR}/gmp)
set(gmp_INSTALL ${prefix}/install)
set(gmp_LIB_DIR ${gmp_INSTALL}/lib)
set(gmp_LIBRARY
${gmp_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gmp${CMAKE_STATIC_LIBRARY_SUFFIX}
${gmp_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gmpxx${CMAKE_STATIC_LIBRARY_SUFFIX}
)
set(gmp_INCLUDE_DIR ${gmp_INSTALL}/include)
# Try to use CONFIGURE_HANDLED_BY_BUILD ON to avoid constantly reconfiguring
if(${CMAKE_VERSION} VERSION_LESS 3.20)
# CMake < 3.20, do not use any extra option
set(gmp_ExternalProject_Add_extra_options)
else()
# CMake >= 3.20
set(gmp_ExternalProject_Add_extra_options "CONFIGURE_HANDLED_BY_BUILD;ON")
endif()
ExternalProject_Add(gmp
PREFIX ${prefix}
URL https://gmplib.org/download/gmp/gmp-6.2.1.tar.xz
URL_MD5 0b82665c4a92fd2ade7440c13fcaa42b
UPDATE_DISCONNECTED true # need this to avoid constant rebuild
PATCH_COMMAND
curl "https://gmplib.org/repo/gmp/raw-rev/5f32dbc41afc" "|" git apply -v
${gmp_ExternalProject_Add_extra_options}
CONFIGURE_COMMAND
${prefix}/src/gmp/configure
--disable-debug --disable-dependency-tracking --enable-cxx --with-pic
--prefix=${gmp_INSTALL}
--disable-shared
BUILD_COMMAND make -j${Ncpu}
INSTALL_COMMAND make -j${Ncpu} install
INSTALL_DIR ${gmp_INSTALL}
TEST_COMMAND ""
BUILD_BYPRODUCTS ${gmp_LIBRARY}
)
ExternalProject_Get_Property(gmp SOURCE_DIR)
set(gmp_LIBRARIES ${gmp_LIBRARY})
add_library(gmp::gmp INTERFACE IMPORTED GLOBAL)
file(MAKE_DIRECTORY ${gmp_INCLUDE_DIR}) # avoid race condition
target_include_directories(gmp::gmp INTERFACE ${gmp_INCLUDE_DIR})
target_link_libraries(gmp::gmp INTERFACE "${gmp_LIBRARIES}") # need the quotes to expand list
add_dependencies(gmp::gmp gmp)
endif()
if(NOT TARGET gmp::gmp)
message(FATAL_ERROR "Creation of target 'gmp::gmp' failed")
endif()
-34
View File
@@ -1,34 +0,0 @@
if(WIN32)
message(STATUS "Third-party: downloading gmp + mpfr")
include(FetchContent)
# CGAL 5+ ships with a single .zip combining GMP + MPFR's precompiled dlls.
# For now we still download them separately.
FetchContent_Declare(
gmp
URL https://cgal.geometryfactory.com/CGAL/precompiled_libs/auxiliary/x64/GMP/5.0.1/gmp-all-CGAL-3.9.zip
URL_MD5 508c1292319c832609329116a8234c9f
)
FetchContent_MakeAvailable(gmp)
FetchContent_Declare(
mpfr
URL https://cgal.geometryfactory.com/CGAL/precompiled_libs/auxiliary/x64/MPFR/3.0.0/mpfr-all-CGAL-3.9.zip
URL_MD5 48840454eef0ff18730050c05028734b
)
FetchContent_MakeAvailable(mpfr)
# FetchContent_Declare(
# gmp_mpfr
# URL https://github.com/CGAL/cgal/releases/download/v5.2.1/CGAL-5.2.1-win64-auxiliary-libraries-gmp-mpfr.zip
# URL_MD5 247f4dca741c6b9a9be76286414070fa
# )
# For CGAL
set(ENV{GMP_DIR} "${gmp_SOURCE_DIR}")
set(ENV{MPFR_DIR} "${mpfr_SOURCE_DIR}")
else()
# On Linux/macOS, gmp+mpfr will be fetched and compiled
endif()
+3 -3
View File
@@ -6,13 +6,13 @@ message(STATUS "Third-party: creating target 'igl::tests_data'")
include(FetchContent)
FetchContent_Declare(
libigl_tests_tata
libigl_tests_data
GIT_REPOSITORY https://github.com/libigl/libigl-tests-data
GIT_TAG 19cedf96d70702d8b3a83eb27934780c542356fe
)
FetchContent_MakeAvailable(libigl_tests_tata)
FetchContent_MakeAvailable(libigl_tests_data)
add_library(igl_tests_data INTERFACE)
add_library(igl::tests_data ALIAS igl_tests_data)
target_compile_definitions(igl_tests_data INTERFACE LIBIGL_DATA_DIR=\"${libigl_tests_tata_SOURCE_DIR}\")
target_compile_definitions(igl_tests_data INTERFACE LIBIGL_DATA_DIR=\"${libigl_tests_data_SOURCE_DIR}\")
+4 -4
View File
@@ -6,13 +6,13 @@ message(STATUS "Third-party: creating target 'igl::tutorial_data'")
include(FetchContent)
FetchContent_Declare(
libigl_tutorial_tata
libigl_tutorial_data
GIT_REPOSITORY https://github.com/libigl/libigl-tutorial-data
GIT_TAG c1f9ede366d02e3531ecbaec5e3769312f31cccd
GIT_TAG 644dd4104843b6d736745d9dafbd70bf8d175648
)
FetchContent_MakeAvailable(libigl_tutorial_tata)
FetchContent_MakeAvailable(libigl_tutorial_data)
add_library(igl_tutorial_data INTERFACE)
add_library(igl::tutorial_data ALIAS igl_tutorial_data)
target_compile_definitions(igl_tutorial_data INTERFACE "-DTUTORIAL_SHARED_PATH=\"${libigl_tutorial_tata_SOURCE_DIR}\"")
target_compile_definitions(igl_tutorial_data INTERFACE "-DTUTORIAL_SHARED_PATH=\"${libigl_tutorial_data_SOURCE_DIR}\"")
-70
View File
@@ -1,70 +0,0 @@
# Expects
# gmp_INCLUDE_DIR
# gmp_LIB_DIR
# gmp_LIBRARIES
if(TARGET mpfr::mpfr)
return()
endif()
# Download precompiled .dll on Windows
if(WIN32)
include(gmp_mpfr)
# Find_package will look for our downloaded lib on Windows, and system-wide on Linux/macOS
find_package(MPFR REQUIRED)
else()
message(STATUS "Third-party: creating target 'mpfr::mpfr'")
include(FetchContent)
include(ProcessorCount)
ProcessorCount(Ncpu)
include(ExternalProject)
set(prefix ${FETCHCONTENT_BASE_DIR}/mpfr)
set(mpfr_INSTALL ${prefix}/install)
set(mpfr_LIBRARY ${mpfr_INSTALL}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}mpfr${CMAKE_STATIC_LIBRARY_SUFFIX})
set(mpfr_INCLUDE_DIR ${mpfr_INSTALL}/include)
# Try to use CONFIGURE_HANDLED_BY_BUILD ON to avoid constantly reconfiguring
if(${CMAKE_VERSION} VERSION_LESS 3.20)
# CMake < 3.20, do not use any extra option
set(mpfr_ExternalProject_Add_extra_options)
else()
# CMake >= 3.20
set(mpfr_ExternalProject_Add_extra_options "CONFIGURE_HANDLED_BY_BUILD;ON")
endif()
ExternalProject_Add(mpfr
PREFIX ${prefix}
DEPENDS gmp
URL https://ftp.gnu.org/gnu/mpfr/mpfr-4.1.0.tar.xz
URL_MD5 bdd3d5efba9c17da8d83a35ec552baef
UPDATE_DISCONNECTED true # need this to avoid constant rebuild
${mpfr_ExternalProject_Add_extra_options} # avoid constant reconfigure
CONFIGURE_COMMAND
${prefix}/src/mpfr/configure
--disable-debug --disable-dependency-tracking --disable-silent-rules --enable-cxx --with-pic
--with-gmp-include=${gmp_INCLUDE_DIR} --with-gmp-lib=${gmp_LIB_DIR}
--disable-shared
--prefix=${mpfr_INSTALL}
--disable-shared
BUILD_COMMAND make -j${Ncpu}
INSTALL_COMMAND make -j${Ncpu} install
INSTALL_DIR ${mpfr_INSTALL}
TEST_COMMAND ""
BUILD_BYPRODUCTS ${mpfr_LIBRARY}
)
#PATCH_COMMAND curl "https://raw.githubusercontent.com/Homebrew/formula-patches/03cf8088210822aa2c1ab544ed58ea04c897d9c4/libtool/configure-big_sur.diff" "|" sed -e "s/configure.orig/configure/g" "|" git apply -v
ExternalProject_Get_Property(mpfr SOURCE_DIR)
set(mpfr_LIBRARIES ${mpfr_LIBRARY})
add_library(mpfr::mpfr INTERFACE IMPORTED GLOBAL)
file(MAKE_DIRECTORY ${mpfr_INCLUDE_DIR}) # avoid race condition
target_include_directories(mpfr::mpfr INTERFACE ${mpfr_INCLUDE_DIR})
target_link_libraries(mpfr::mpfr INTERFACE "${mpfr_LIBRARIES}") # need the quotes to expand list
# This is necessary to ensure that mpfr appears before gmp in link order.
# Otherwise undefined reference errors occur at link time on Linux with gcc
target_link_libraries(mpfr::mpfr INTERFACE "${gmp_LIBRARIES}")
add_dependencies(mpfr::mpfr mpfr)
endif()
if(NOT TARGET mpfr::mpfr)
message(FATAL_ERROR "Creation of target 'mpfr::mpfr' failed")
endif()
+1 -1
View File
@@ -8,7 +8,7 @@ include(FetchContent)
FetchContent_Declare(
predicates
GIT_REPOSITORY https://github.com/libigl/libigl-predicates.git
GIT_TAG 488242fa2b1f98a9c5bd1441297fb4a99a6a9ae4
GIT_TAG decb7bc1260e689cbe008109e3cc5d3a5a433aea
)
FetchContent_MakeAvailable(predicates)
+16
View File
@@ -0,0 +1,16 @@
if(TARGET spectra::spectra)
return()
endif()
include(FetchContent)
message(STATUS "Third-party: creating target 'spectra::spectra'")
# Use fork because yixuan/spectra struggles to find Eigen3
FetchContent_Declare(
Spectra
GIT_REPOSITORY https://github.com/alecjacobson/spectra/
GIT_TAG bbdc521b70a733c52ebfc0ac1484c82e13c3d140
)
FetchContent_MakeAvailable(Spectra)
add_library(spectra::spectra ALIAS Spectra)
+1 -1
View File
@@ -8,7 +8,7 @@ include(FetchContent)
FetchContent_Declare(
tetgen
GIT_REPOSITORY https://github.com/libigl/tetgen.git
GIT_TAG 4f3bfba3997f20aa1f96cfaff604313a8c2c85b6
GIT_TAG e05aca7df74e3f531bc35733ed87d36d437266c5
)
FetchContent_MakeAvailable(tetgen)
+1 -1
View File
@@ -8,7 +8,7 @@ include(FetchContent)
FetchContent_Declare(
triangle
GIT_REPOSITORY https://github.com/libigl/triangle.git
GIT_TAG 3ee6cac2230f0fe1413879574f741c7b6da11221
GIT_TAG 62f02db9ab4ff4b62d5ff82a77c8ea458c84c23a
)
FetchContent_MakeAvailable(triangle)
File diff suppressed because it is too large Load Diff
+2729
View File
File diff suppressed because it is too large Load Diff
+54
View File
@@ -0,0 +1,54 @@
# libigl - A simple C++ geometry processing library
This detailed documentation browser is automatically generated from the comments
in libigl header (.h) files.
In general, each [libigl function](./namespaceigl.html#func-members) (e.g., `igl::func`) will be defined in a
correspondingly named header file (e.g., `#include <igl/func.h>`).
The _core_ library only depends on the standard template library (`std::`) and
Eigen. These functions reside directly the [`igl::` namespace](./namespaceigl.html)
Functions with further dependencies reside in a corresonding sub-namespace. For
example, the function `igl::spectra::lscm` depends on the Spectra library so it
resides in the [`igl::spectra::` namespace](./namespaceigl_1_1spectra.html).
Functions which depend on external code under a copyleft license reside in the
[`igl::copyleft::` namepsace](file:///Users/alecjacobson/Repos/libigl/dox/namespaceigl_1_1copyleft.html).
Most libigl functions are templated over the Eigen matrix inputs and outputs.
Callers can choose their own scalar types (e.g., `double`/`float`) and storage
orders (`Eigen::ColMajor`/`Eigen::RowMajor`). Libigl can be used as a:
- **header only library** (via CMake, make sure
`LIBIGL_USE_STATIC_LIBRARY=OFF`) and insure that `IGL_STATIC_LIBRARY` is
_not_ defined_ when compiling --- easiest if you're new to libigl, or
- **static library** (`LIBIGL_USE_STATIC_LIBRARY=ON``IGL_STATIC_LIBRARY` is
defined) --- speeds up repeated compilation.
The libigl static library is filled with _explicit template instantiations_ for
common Eigen inputs and outputs. If the library doesn't contain your types, you
may get some form of linker error (e.g., `Undefined symbols for architecture`,
`undefined reference to` or `unresolved external symbol`).
You can fix this by:
1. Switching to header only mode for your project,
2. Making a file in your project to compile the missing templates. E.g., `my_templates.cpp`
```cpp
#ifdef IGL_STATIC_LIBRARY
#undef IGL_STATIC_LIBRARY
#endif
#include <igl/per_vertex_normals.h>
template void igl::per_vertex_normals<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> >&);
```
3. [Submit a PR](https://github.com/libigl/libigl/pulls) containing your missing template to the development branch of libigl
4. Change your input/output types to match existing templates (e.g., `Eigen::MatrixXd`).
https://libigl.github.io/
https://github.com/libigl/libigl/
+1032 -323
View File
File diff suppressed because it is too large Load Diff
+636 -194
View File
File diff suppressed because it is too large Load Diff
+12 -15
View File
@@ -9,27 +9,24 @@
#define IGL_ARAPENERGYTYPE_H
namespace igl
{
// ARAP_ENERGY_TYPE_SPOKES "As-rigid-as-possible Surface Modeling" by [Sorkine and
// Alexa 2007], rotations defined at vertices affecting incident edges,
// default
// ARAP_ENERGY_TYPE_SPOKES-AND-RIMS Adapted version of "As-rigid-as-possible Surface
// Modeling" by [Sorkine and Alexa 2007] presented in section 4.2 of or
// "A simple geometric model for elastic deformation" by [Chao et al.
// 2010], rotations defined at vertices affecting incident edges and
// opposite edges
// ARAP_ENERGY_TYPE_ELEMENTS "A local-global approach to mesh parameterization" by
// [Liu et al. 2010] or "A simple geometric model for elastic
// deformation" by [Chao et al. 2010], rotations defined at elements
// (triangles or tets)
// ARAP_ENERGY_TYPE_DEFAULT Choose one automatically: spokes and rims
// for surfaces, elements for planar meshes and tets (not fully
// supported)
/// Enum for choosing ARAP energy type
enum ARAPEnergyType
{
/// "As-rigid-as-possible Surface Modeling" by [Sorkine and Alexa 2007],
/// rotations defined at vertices affecting incident edges, default
ARAP_ENERGY_TYPE_SPOKES = 0,
/// Adapted version of "As-rigid-as-possible Surface Modeling" by [Sorkine
/// and Alexa 2007] presented in section 4.2 of or "A simple geometric model
/// for elastic deformation" by [Chao et al.\ 2010], rotations defined at
/// vertices affecting incident edges and opposite edges
ARAP_ENERGY_TYPE_SPOKES_AND_RIMS = 1,
/// "A local-global approach to mesh parameterization" by [Liu et al.\ 2010]
/// or "A simple geometric model for elastic deformation" by [Chao et al.\ 2010], rotations defined at elements (triangles or tets)
ARAP_ENERGY_TYPE_ELEMENTS = 2,
/// Choose one automatically: spokes and rims for surfaces, elements for
/// planar meshes and tets (not fully supported)
ARAP_ENERGY_TYPE_DEFAULT = 3,
/// Total number of types
NUM_ARAP_ENERGY_TYPES = 4
};
}
+13 -12
View File
@@ -6,6 +6,7 @@
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "AtA_cached.h"
#include "IGL_ASSERT.h"
#include <iostream>
#include <vector>
@@ -34,12 +35,12 @@ IGL_INLINE void igl::AtA_cached_precompute(
int col = k;
int row = *(A.innerIndexPtr()+l);
int value_index = l;
assert(col < A.cols());
assert(col >= 0);
assert(row < A.rows());
assert(row >= 0);
assert(value_index >= 0);
assert(value_index < A.nonZeros());
IGL_ASSERT(col < A.cols());
IGL_ASSERT(col >= 0);
IGL_ASSERT(row < A.rows());
IGL_ASSERT(row >= 0);
IGL_ASSERT(value_index >= 0);
IGL_ASSERT(value_index < A.nonZeros());
Col_RowPtr[col].push_back(row);
Col_IndexPtr[col].push_back(value_index);
@@ -74,12 +75,12 @@ IGL_INLINE void igl::AtA_cached_precompute(
int col = k;
int row = *(AtA.innerIndexPtr()+l);
int value_index = l;
assert(col < AtA.cols());
assert(col >= 0);
assert(row < AtA.rows());
assert(row >= 0);
assert(value_index >= 0);
assert(value_index < AtA.nonZeros());
IGL_ASSERT(col < AtA.cols());
IGL_ASSERT(col >= 0);
IGL_ASSERT(row < AtA.rows());
IGL_ASSERT(row >= 0);
IGL_ASSERT(value_index >= 0);
IGL_ASSERT(value_index < AtA.nonZeros());
data.I_outer.push_back(data.I_row.size());
+32 -20
View File
@@ -13,40 +13,47 @@
#include <Eigen/Sparse>
namespace igl
{
/// Hold precomputed data for AtA_cached
struct AtA_cached_data
{
// Weights
/// Weights (diagonal of W)
Eigen::VectorXd W;
// Flatten composition rules
/// @private
std::vector<int> I_row;
/// @private
std::vector<int> I_col;
/// @private
std::vector<int> I_w;
// For each entry of AtA, points to the beginning
// of the composition rules
/// @private
std::vector<int> I_outer;
};
// Computes At * W * A, where A is sparse and W is diagonal. Divides the
// construction in two phases, one
// for fixing the sparsity pattern, and one to populate it with values. Compared to
// evaluating it directly, this version is slower for the first time (since it requires a
// precomputation), but faster to the subsequent evaluations.
//
// Input:
// A m x n sparse matrix
// data stores the precomputed sparsity pattern, data.W contains the optional diagonal weights (stored as a dense vector). If W is not provided, it is replaced by the identity.
// Outputs:
// AtA m by m matrix computed as AtA * W * A
//
// Example:
// AtA_data = igl::AtA_cached_data();
// AtA_data.W = W;
// if (s.AtA.rows() == 0)
// igl::AtA_cached_precompute(s.A,s.AtA_data,s.AtA);
// else
// igl::AtA_cached(s.A,s.AtA_data,s.AtA);
/// Computes At * W * A, where A is sparse and W is diagonal.
///
/// Divides the construction in two phases, one for fixing the sparsity
/// pattern, and one to populate it with values. Compared to evaluating it
/// directly, this version is slower for the first time (since it requires a
/// precomputation), but faster to the subsequent evaluations.
///
/// @param[in] A m x n sparse matrix
/// @param[in,out] data stores the precomputed sparsity pattern, data.W contains the optional diagonal weights (stored as a dense vector). If W is not provided, it is replaced by the identity.
/// @param[out] AtA m by m matrix computed as AtA * W * A
///
/// #### Example:
///
/// \code{cpp}
/// AtA_data = igl::AtA_cached_data();
/// AtA_data.W = W;
/// if (s.AtA.rows() == 0)
/// igl::AtA_cached_precompute(s.A,s.AtA_data,s.AtA);
/// else
/// igl::AtA_cached(s.A,s.AtA_data,s.AtA);
/// \endcode
template <typename Scalar>
IGL_INLINE void AtA_cached_precompute(
const Eigen::SparseMatrix<Scalar>& A,
@@ -54,6 +61,11 @@ namespace igl
Eigen::SparseMatrix<Scalar>& AtA
);
/// Computes At * W * A, where A is sparse and W is diagonal precomputed into data.
///
/// @param[in] A m x n sparse matrix
/// @param[in] data stores the precomputed sparsity pattern, data.W contains the optional diagonal weights (stored as a dense vector). If W is not provided, it is replaced by the identity.
/// @param[out] AtA m by m matrix computed as AtA * W * A
template <typename Scalar>
IGL_INLINE void AtA_cached(
const Eigen::SparseMatrix<Scalar>& A,
+19
View File
@@ -0,0 +1,19 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2025 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_COLLAPSE_EDGE_NULL_H
#define IGL_COLLAPSE_EDGE_NULL_H
namespace igl
{
#ifndef IGL_COLLAPSE_EDGE_NULL
/// Special value for indicating a null vertex index as the result of a
/// collapsed edge.
#define IGL_COLLAPSE_EDGE_NULL 0
#endif
}
#endif
+16 -5
View File
@@ -7,12 +7,23 @@
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_C_STR_H
#define IGL_C_STR_H
// http://stackoverflow.com/a/2433143/148668
// Suppose you have a function:
// void func(const char * c);
// Then you can write:
// func(C_STR("foo"<<1<<"bar"));
#include <sstream>
#include <string>
/// Convert a stream of things to a const char *.
///
/// Suppose you have a function:
/// \code{cpp}
/// void func(const char * c);
/// \endcode
/// Then you can write:
/// \code{cpp}
/// func(C_STR("foo"<<1<<"bar"));
/// \endcode
/// which is equivalent to:
/// \code{cpp}
/// func("foo1bar");
/// \endcode
///
// http://stackoverflow.com/a/2433143/148668
#define C_STR(X) static_cast<std::ostringstream&>(std::ostringstream().flush() << X).str().c_str()
#endif
-359
View File
@@ -1,359 +0,0 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_CAMERA_H
#define IGL_CAMERA_H
// you're idiot, M$!
#if defined(_WIN32)
#undef far
#undef near
#endif
#include <Eigen/Geometry>
#include <Eigen/Core>
#include "PI.h"
#define IGL_CAMERA_MIN_ANGLE 5.0
namespace igl
{
// A simple camera class. The camera stores projection parameters (field of
// view angle, aspect ratio, near and far clips) as well as a rigid
// transformation *of the camera as if it were also a scene object*. Thus, the
// **inverse** of this rigid transformation is the modelview transformation.
class Camera
{
public:
// On windows you might need: -fno-delayed-template-parsing
//static constexpr double IGL_CAMERA_MIN_ANGLE = 5.;
// m_angle Field of view angle in degrees {45}
// m_aspect Aspect ratio {1}
// m_near near clipping plane {1e-2}
// m_far far clipping plane {100}
// m_at_dist distance of looking at point {1}
// m_orthographic whether to use othrographic projection {false}
// m_rotation_conj Conjugate of rotation part of rigid transformation of
// camera {identity}. Note: we purposefully store the conjugate because
// this is what TW_TYPE_QUAT4D is expecting.
// m_translation Translation part of rigid transformation of camera
// {(0,0,1)}
double m_angle, m_aspect, m_near, m_far, m_at_dist;
bool m_orthographic;
Eigen::Quaterniond m_rotation_conj;
Eigen::Vector3d m_translation;
public:
inline Camera();
inline virtual ~Camera(){}
// Return projection matrix that takes relative camera coordinates and
// transforms it to viewport coordinates
//
// Note:
//
// if(m_angle > 0)
// {
// gluPerspective(m_angle,m_aspect,m_near,m_at_dist+m_far);
// }else
// {
// gluOrtho(-0.5*aspect,0.5*aspect,-0.5,0.5,m_at_dist+m_near,m_far);
// }
//
// Is equivalent to
//
// glMultMatrixd(projection().data());
//
inline Eigen::Matrix4d projection() const;
// Return an Affine transformation (rigid actually) that
// takes relative coordinates and tramsforms them into world 3d
// coordinates: moves the camera into the scene.
inline Eigen::Affine3d affine() const;
// Return an Affine transformation (rigid actually) that puts the takes a
// world 3d coordinate and transforms it into the relative camera
// coordinates: moves the scene in front of the camera.
//
// Note:
//
// gluLookAt(
// eye()(0), eye()(1), eye()(2),
// at()(0), at()(1), at()(2),
// up()(0), up()(1), up()(2));
//
// Is equivalent to
//
// glMultMatrixd(camera.inverse().matrix().data());
//
// See also: affine, eye, at, up
inline Eigen::Affine3d inverse() const;
// Returns world coordinates position of center or "eye" of camera.
inline Eigen::Vector3d eye() const;
// Returns world coordinate position of a point "eye" is looking at.
inline Eigen::Vector3d at() const;
// Returns world coordinate unit vector of "up" vector
inline Eigen::Vector3d up() const;
// Return top right corner of unit plane in relative coordinates, that is
// (w/2,h/2,1)
inline Eigen::Vector3d unit_plane() const;
// Move dv in the relative coordinate frame of the camera (move the FPS)
//
// Inputs:
// dv (x,y,z) displacement vector
//
inline void dolly(const Eigen::Vector3d & dv);
// "Scale zoom": Move `eye`, but leave `at`
//
// Input:
// s amount to scale distance to at
inline void push_away(const double s);
// Aka "Hitchcock", "Vertigo", "Spielberg" or "Trombone" zoom:
// simultaneously dolly while changing angle so that `at` not only stays
// put in relative coordinates but also projected coordinates. That is
//
// Inputs:
// da change in angle in degrees
inline void dolly_zoom(const double da);
// Turn around eye so that rotation is now q
//
// Inputs:
// q new rotation as quaternion
inline void turn_eye(const Eigen::Quaterniond & q);
// Orbit around at so that rotation is now q
//
// Inputs:
// q new rotation as quaternion
inline void orbit(const Eigen::Quaterniond & q);
// Rotate and translate so that camera is situated at "eye" looking at "at"
// with "up" pointing up.
//
// Inputs:
// eye (x,y,z) coordinates of eye position
// at (x,y,z) coordinates of at position
// up (x,y,z) coordinates of up vector
inline void look_at(
const Eigen::Vector3d & eye,
const Eigen::Vector3d & at,
const Eigen::Vector3d & up);
// Needed any time Eigen Structures are used as class members
// http://eigen.tuxfamily.org/dox-devel/group__TopicStructHavingEigenMembers.html
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};
}
// Implementation
#include "PI.h"
#include "EPS.h"
#include <cmath>
#include <iostream>
#include <cassert>
inline igl::Camera::Camera():
m_angle(45.0),m_aspect(1),m_near(1e-2),m_far(100),m_at_dist(1),
m_orthographic(false),
m_rotation_conj(1,0,0,0),
m_translation(0,0,1)
{
}
inline Eigen::Matrix4d igl::Camera::projection() const
{
Eigen::Matrix4d P;
using namespace std;
const double far = m_at_dist + m_far;
const double near = m_near;
// http://stackoverflow.com/a/3738696/148668
if(m_orthographic)
{
const double f = 0.5;
const double left = -f*m_aspect;
const double right = f*m_aspect;
const double bottom = -f;
const double top = f;
const double tx = (right+left)/(right-left);
const double ty = (top+bottom)/(top-bottom);
const double tz = (far+near)/(far-near);
const double z_fix = 0.5 /m_at_dist / tan(m_angle*0.5 * (igl::PI/180.) );
P<<
z_fix*2./(right-left), 0, 0, -tx,
0, z_fix*2./(top-bottom), 0, -ty,
0, 0, -z_fix*2./(far-near), -tz,
0, 0, 0, 1;
}else
{
const double yScale = tan(PI*0.5 - 0.5*m_angle*PI/180.);
// http://stackoverflow.com/a/14975139/148668
const double xScale = yScale/m_aspect;
P<<
xScale, 0, 0, 0,
0, yScale, 0, 0,
0, 0, -(far+near)/(far-near), -1,
0, 0, -2.*near*far/(far-near), 0;
P = P.transpose().eval();
}
return P;
}
inline Eigen::Affine3d igl::Camera::affine() const
{
using namespace Eigen;
Affine3d t = Affine3d::Identity();
t.rotate(m_rotation_conj.conjugate());
t.translate(m_translation);
return t;
}
inline Eigen::Affine3d igl::Camera::inverse() const
{
using namespace Eigen;
Affine3d t = Affine3d::Identity();
t.translate(-m_translation);
t.rotate(m_rotation_conj);
return t;
}
inline Eigen::Vector3d igl::Camera::eye() const
{
using namespace Eigen;
return affine() * Vector3d(0,0,0);
}
inline Eigen::Vector3d igl::Camera::at() const
{
using namespace Eigen;
return affine() * (Vector3d(0,0,-1)*m_at_dist);
}
inline Eigen::Vector3d igl::Camera::up() const
{
using namespace Eigen;
Affine3d t = Affine3d::Identity();
t.rotate(m_rotation_conj.conjugate());
return t * Vector3d(0,1,0);
}
inline Eigen::Vector3d igl::Camera::unit_plane() const
{
// Distance of center pixel to eye
const double d = 1.0;
const double a = m_aspect;
const double theta = m_angle*PI/180.;
const double w =
2.*sqrt(-d*d/(a*a*pow(tan(0.5*theta),2.)-1.))*a*tan(0.5*theta);
const double h = w/a;
return Eigen::Vector3d(w*0.5,h*0.5,-d);
}
inline void igl::Camera::dolly(const Eigen::Vector3d & dv)
{
m_translation += dv;
}
inline void igl::Camera::push_away(const double s)
{
using namespace Eigen;
#ifndef NDEBUG
Vector3d old_at = at();
#endif
const double old_at_dist = m_at_dist;
m_at_dist = old_at_dist * s;
dolly(Vector3d(0,0,1)*(m_at_dist - old_at_dist));
assert((old_at-at()).squaredNorm() < DOUBLE_EPS);
}
inline void igl::Camera::dolly_zoom(const double da)
{
using namespace std;
using namespace Eigen;
#ifndef NDEBUG
Vector3d old_at = at();
#endif
const double old_angle = m_angle;
if(old_angle + da < IGL_CAMERA_MIN_ANGLE)
{
m_orthographic = true;
}else if(old_angle + da > IGL_CAMERA_MIN_ANGLE)
{
m_orthographic = false;
}
if(!m_orthographic)
{
m_angle += da;
m_angle = min(89.,max(IGL_CAMERA_MIN_ANGLE,m_angle));
// change in distance
const double s =
(2.*tan(old_angle/2./180.*igl::PI)) /
(2.*tan(m_angle/2./180.*igl::PI)) ;
const double old_at_dist = m_at_dist;
m_at_dist = old_at_dist * s;
dolly(Vector3d(0,0,1)*(m_at_dist - old_at_dist));
assert((old_at-at()).squaredNorm() < DOUBLE_EPS);
}
}
inline void igl::Camera::turn_eye(const Eigen::Quaterniond & q)
{
using namespace Eigen;
Vector3d old_eye = eye();
// eye should be fixed
//
// eye_1 = R_1 * t_1 = eye_0
// t_1 = R_1' * eye_0
m_rotation_conj = q.conjugate();
m_translation = m_rotation_conj * old_eye;
assert((old_eye - eye()).squaredNorm() < DOUBLE_EPS);
}
inline void igl::Camera::orbit(const Eigen::Quaterniond & q)
{
using namespace Eigen;
Vector3d old_at = at();
// at should be fixed
//
// at_1 = R_1 * t_1 - R_1 * z = at_0
// t_1 = R_1' * (at_0 + R_1 * z)
m_rotation_conj = q.conjugate();
m_translation =
m_rotation_conj *
(old_at +
m_rotation_conj.conjugate() * Vector3d(0,0,1) * m_at_dist);
assert((old_at - at()).squaredNorm() < DOUBLE_EPS);
}
inline void igl::Camera::look_at(
const Eigen::Vector3d & eye,
const Eigen::Vector3d & at,
const Eigen::Vector3d & up)
{
using namespace Eigen;
using namespace std;
// http://www.opengl.org/sdk/docs/man2/xhtml/gluLookAt.xml
// Normalize vector from at to eye
Vector3d F = eye-at;
m_at_dist = F.norm();
F.normalize();
// Project up onto plane orthogonal to F and normalize
assert(up.cross(F).norm() > DOUBLE_EPS && "(eye-at) x up ≈ 0");
const Vector3d proj_up = (up-(up.dot(F))*F).normalized();
Quaterniond a,b;
a.setFromTwoVectors(Vector3d(0,0,-1),-F);
b.setFromTwoVectors(a*Vector3d(0,1,0),proj_up);
m_rotation_conj = (b*a).conjugate();
m_translation = m_rotation_conj * eye;
//cout<<"m_at_dist: "<<m_at_dist<<endl;
//cout<<"proj_up: "<<proj_up.transpose()<<endl;
//cout<<"F: "<<F.transpose()<<endl;
//cout<<"eye(): "<<this->eye().transpose()<<endl;
//cout<<"at(): "<<this->at().transpose()<<endl;
//cout<<"eye()-at(): "<<(this->eye()-this->at()).normalized().transpose()<<endl;
//cout<<"eye-this->eye(): "<<(eye-this->eye()).squaredNorm()<<endl;
assert( (eye-this->eye()).squaredNorm() < DOUBLE_EPS);
//assert((F-(this->eye()-this->at()).normalized()).squaredNorm() <
// DOUBLE_EPS);
assert( (at-this->at()).squaredNorm() < DOUBLE_EPS);
//assert( (proj_up-this->up()).squaredNorm() < DOUBLE_EPS);
}
#endif
+6 -2
View File
@@ -10,13 +10,17 @@
#include "igl_inline.h"
namespace igl
{
// Define a standard value for double epsilon
/// Standard value for double epsilon
const double DOUBLE_EPS = 1.0e-14;
/// Standard value for double epsilon²
const double DOUBLE_EPS_SQ = 1.0e-28;
/// Standard value for single epsilon
const float FLOAT_EPS = 1.0e-7f;
/// Standard value for single epsilon²
const float FLOAT_EPS_SQ = 1.0e-14f;
// Function returning EPS for corresponding type
/// Function returning EPS for corresponding type
template <typename S_type> IGL_INLINE S_type EPS();
/// Function returning EPS_SQ for corresponding type
template <typename S_type> IGL_INLINE S_type EPS_SQ();
// Template specializations for float and double
template <> IGL_INLINE float EPS<float>();
+114 -84
View File
@@ -85,7 +85,9 @@
#include <sys/types.h>
#include <stdint.h>
namespace igl { namespace FastWindingNumber {
namespace igl {
/// @private
namespace FastWindingNumber {
/*
* Integer types
@@ -198,10 +200,10 @@ typedef union SYS_FPRealUnionT<fpreal64> SYS_FPRealUnionD;
/// Asserts are disabled
/// @{
#define UT_ASSERT_P(ZZ) ((void)0)
#define UT_ASSERT(ZZ) ((void)0)
#define UT_ASSERT_MSG_P(ZZ, MM) ((void)0)
#define UT_ASSERT_MSG(ZZ, MM) ((void)0)
#define UT_IGL_ASSERT_P(ZZ) ((void)0)
#define UT_IGL_ASSERT(ZZ) ((void)0)
#define UT_IGL_ASSERT_MSG_P(ZZ, MM) ((void)0)
#define UT_IGL_ASSERT_MSG(ZZ, MM) ((void)0)
/// @}
}}
@@ -242,7 +244,9 @@ typedef union SYS_FPRealUnionT<fpreal64> SYS_FPRealUnionD;
#include <limits>
#include <math.h>
namespace igl { namespace FastWindingNumber {
namespace igl {
/// @private
namespace FastWindingNumber {
// NOTE:
// These have been carefully written so that in the case of equality
@@ -383,7 +387,9 @@ static inline fpreal64 SYSabs(fpreal64 a) { return ::fabs(a); }
#pragma warning(pop)
#endif
namespace igl { namespace FastWindingNumber {
namespace igl {
/// @private
namespace FastWindingNumber {
typedef __m128 v4sf;
typedef __m128i v4si;
@@ -745,7 +751,9 @@ vm_allbits(const v4si &a)
#include <cmath>
namespace igl { namespace FastWindingNumber {
namespace igl {
/// @private
namespace FastWindingNumber {
struct v4si {
int32 v[4];
@@ -1174,7 +1182,9 @@ int SYS_FORCE_INLINE _mm_movemask_ps(const v4sf& v) {
namespace igl { namespace FastWindingNumber {
namespace igl {
/// @private
namespace FastWindingNumber {
class v4uf;
@@ -1628,7 +1638,9 @@ typedef v4uu v4ui;
#include <type_traits>
#include <string.h>
namespace igl { namespace FastWindingNumber {
namespace igl {
/// @private
namespace FastWindingNumber {
/// This routine describes how to change the size of an array.
/// It must increase the current_size by at least one!
@@ -1949,7 +1961,7 @@ public:
/// asserts are enabled.
T & operator()(exint i)
{
UT_ASSERT_P(i >= 0 && i < mySize);
UT_IGL_ASSERT_P(i >= 0 && i < mySize);
return myData[i];
}
/// Const subscript operator
@@ -1957,7 +1969,7 @@ public:
/// asserts are enabled.
const T & operator()(exint i) const
{
UT_ASSERT_P(i >= 0 && i < mySize);
UT_IGL_ASSERT_P(i >= 0 && i < mySize);
return myData[i];
}
@@ -1966,7 +1978,7 @@ public:
/// asserts are enabled.
T & operator[](exint i)
{
UT_ASSERT_P(i >= 0 && i < mySize);
UT_IGL_ASSERT_P(i >= 0 && i < mySize);
return myData[i];
}
/// Const subscript operator
@@ -1974,7 +1986,7 @@ public:
/// asserts are enabled.
const T & operator[](exint i) const
{
UT_ASSERT_P(i >= 0 && i < mySize);
UT_IGL_ASSERT_P(i >= 0 && i < mySize);
return myData[i];
}
@@ -1983,7 +1995,7 @@ public:
/// class types.
T & forcedRef(exint i)
{
UT_ASSERT_P(i >= 0);
UT_IGL_ASSERT_P(i >= 0);
if (i >= mySize)
bumpSize(i+1);
return myData[i];
@@ -1998,12 +2010,12 @@ public:
T & last()
{
UT_ASSERT_P(mySize);
UT_IGL_ASSERT_P(mySize);
return myData[mySize-1];
}
const T & last() const
{
UT_ASSERT_P(mySize);
UT_IGL_ASSERT_P(mySize);
return myData[mySize-1];
}
@@ -2423,7 +2435,9 @@ private:
#include <stdlib.h>
#include <string.h>
namespace igl { namespace FastWindingNumber {
namespace igl {
/// @private
namespace FastWindingNumber {
// Implemented in UT_Array.C
extern void ut_ArrayImplFree(void *p);
@@ -2527,7 +2541,7 @@ UT_Array<T>::insert(exint index)
}
bumpCapacity(mySize + 1);
UT_ASSERT_P(index >= 0);
UT_IGL_ASSERT_P(index >= 0);
::memmove((void *)&myData[index+1], (void *)&myData[index],
((mySize-index)*sizeof(T)));
@@ -2585,7 +2599,7 @@ template <typename T>
inline void
UT_Array<T>::appendMultiple(const T &t, exint count)
{
UT_ASSERT_P(count >= 0);
UT_IGL_ASSERT_P(count >= 0);
if (count <= 0)
return;
if (mySize + count >= myCapacity)
@@ -2709,8 +2723,8 @@ template <typename T>
inline void
UT_Array<T>::removeRange(exint begin_i, exint end_i)
{
UT_ASSERT(begin_i <= end_i);
UT_ASSERT(end_i <= size());
UT_IGL_ASSERT(begin_i <= end_i);
UT_IGL_ASSERT(end_i <= size());
if (end_i < size())
{
trivialDestructRange(myData + begin_i, end_i - begin_i);
@@ -2724,10 +2738,10 @@ template <typename T>
inline void
UT_Array<T>::extractRange(exint begin_i, exint end_i, UT_Array<T>& dest)
{
UT_ASSERT_P(begin_i >= 0);
UT_ASSERT_P(begin_i <= end_i);
UT_ASSERT_P(end_i <= size());
UT_ASSERT(this != &dest);
UT_IGL_ASSERT_P(begin_i >= 0);
UT_IGL_ASSERT_P(begin_i <= end_i);
UT_IGL_ASSERT_P(end_i <= size());
UT_IGL_ASSERT(this != &dest);
exint nelements = end_i - begin_i;
@@ -2818,7 +2832,7 @@ UT_Array<T>::removeIf(IsEqual is_equal)
{
if (!is_equal(myData[idx]))
{
UT_ASSERT(idx != dst);
UT_IGL_ASSERT(idx != dst);
myData[dst] = myData[idx];
dst++;
}
@@ -2893,7 +2907,7 @@ UT_Array<T>::setCapacity(exint capacity)
T *prev = myData;
myData = (T *)malloc(sizeof(T) * capacity);
// myData is safe because we're already a stack buffer
UT_ASSERT_P(isHeapBuffer());
UT_IGL_ASSERT_P(isHeapBuffer());
if (mySize > 0)
memcpy((void *)myData, (void *)prev, sizeof(T) * mySize);
myCapacity = capacity;
@@ -2901,7 +2915,7 @@ UT_Array<T>::setCapacity(exint capacity)
else
{
// Keep myCapacity unchanged in this case
UT_ASSERT_P(capacity >= mySize && capacity <= myCapacity);
UT_IGL_ASSERT_P(capacity >= mySize && capacity <= myCapacity);
}
return;
}
@@ -2941,7 +2955,7 @@ UT_Array<T>::setCapacity(exint capacity)
}
myCapacity = capacity;
UT_ASSERT(myData);
UT_IGL_ASSERT(myData);
}
template <typename T>
@@ -3086,7 +3100,9 @@ UT_Array<T>::operator!=(const UT_Array<T> &a) const
#include <utility>
#include <stddef.h>
namespace igl { namespace FastWindingNumber {
namespace igl {
/// @private
namespace FastWindingNumber {
/// An array class with the small buffer optimization, making it ideal for
/// cases when you know it will only contain a few elements at the expense of
@@ -3103,14 +3119,14 @@ public:
// easily suppress this because it has to be done in the caller at
// instantiation time. Instead, punt to a runtime check instead.
#if defined(__clang__) || defined(_MSC_VER)
#define UT_SMALL_ARRAY_SIZE_ASSERT() \
#define UT_SMALL_ARRAY_SIZE_IGL_ASSERT() \
using ThisT = UT_SmallArray<T,MAX_BYTES>; \
static_assert(offsetof(ThisT, myBuffer) == sizeof(UT_Array<T>), \
"In order for UT_Array's checks for whether it needs to free the buffer to work, " \
"the buffer must be exactly following the base class memory.")
#else
#define UT_SMALL_ARRAY_SIZE_ASSERT() \
UT_ASSERT_P(!UT_Array<T>::isHeapBuffer());
#define UT_SMALL_ARRAY_SIZE_IGL_ASSERT() \
UT_IGL_ASSERT_P(!UT_Array<T>::isHeapBuffer());
#endif
/// Default construction
@@ -3118,7 +3134,7 @@ public:
: UT_Array<T>(/*capacity*/0)
{
UT_Array<T>::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS);
UT_SMALL_ARRAY_SIZE_ASSERT();
UT_SMALL_ARRAY_SIZE_IGL_ASSERT();
}
/// Copy constructor
@@ -3127,14 +3143,14 @@ public:
: UT_Array<T>(/*capacity*/0)
{
UT_Array<T>::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS);
UT_SMALL_ARRAY_SIZE_ASSERT();
UT_SMALL_ARRAY_SIZE_IGL_ASSERT();
UT_Array<T>::operator=(copy);
}
explicit UT_SmallArray(const UT_SmallArray<T,MAX_BYTES> &copy)
: UT_Array<T>(/*capacity*/0)
{
UT_Array<T>::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS);
UT_SMALL_ARRAY_SIZE_ASSERT();
UT_SMALL_ARRAY_SIZE_IGL_ASSERT();
UT_Array<T>::operator=(copy);
}
/// @}
@@ -3144,13 +3160,13 @@ public:
UT_SmallArray(UT_Array<T> &&movable) noexcept
{
UT_Array<T>::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS);
UT_SMALL_ARRAY_SIZE_ASSERT();
UT_SMALL_ARRAY_SIZE_IGL_ASSERT();
UT_Array<T>::operator=(std::move(movable));
}
UT_SmallArray(UT_SmallArray<T,MAX_BYTES> &&movable) noexcept
{
UT_Array<T>::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS);
UT_SMALL_ARRAY_SIZE_ASSERT();
UT_SMALL_ARRAY_SIZE_IGL_ASSERT();
UT_Array<T>::operator=(std::move(movable));
}
/// @}
@@ -3159,11 +3175,11 @@ public:
explicit UT_SmallArray(std::initializer_list<T> init)
{
UT_Array<T>::unsafeShareData((T*)myBuffer, 0, MAX_ELEMS);
UT_SMALL_ARRAY_SIZE_ASSERT();
UT_SMALL_ARRAY_SIZE_IGL_ASSERT();
UT_Array<T>::operator=(init);
}
#undef UT_SMALL_ARRAY_SIZE_ASSERT
#undef UT_SMALL_ARRAY_SIZE_IGL_ASSERT
/// Assignment operator
/// @{
@@ -3242,7 +3258,9 @@ private:
namespace igl { namespace FastWindingNumber {
namespace igl {
/// @private
namespace FastWindingNumber {
template<typename T,exint SIZE,bool INSTANTIATED=false>
class UT_FixedVector
@@ -3285,12 +3303,12 @@ public:
SYS_FORCE_INLINE const T &operator[](exint i) const noexcept
{
UT_ASSERT_P(i >= 0 && i < SIZE);
UT_IGL_ASSERT_P(i >= 0 && i < SIZE);
return vec[i];
}
SYS_FORCE_INLINE T &operator[](exint i) noexcept
{
UT_ASSERT_P(i >= 0 && i < SIZE);
UT_IGL_ASSERT_P(i >= 0 && i < SIZE);
return vec[i];
}
@@ -3646,7 +3664,9 @@ struct UT_FixedVectorTraits<UT_FixedVector<T,SIZE,INSTANTIATED> >
#include <thread> // This is just included for std::thread::hardware_concurrency()
namespace igl { namespace FastWindingNumber {
namespace igl {
/// @private
namespace FastWindingNumber {
namespace UT_Thread { inline int getNumProcessors() {
return std::thread::hardware_concurrency();
}}
@@ -3796,9 +3816,9 @@ namespace UT_Thread { inline int getNumProcessors() {
//{
// const size_t num_processors( UT_Thread::getNumProcessors() );
//
// UT_ASSERT( num_processors >= 1 );
// UT_ASSERT( min_grain_size >= 1 );
// UT_ASSERT( subscribe_ratio >= 0 );
// UT_IGL_ASSERT( num_processors >= 1 );
// UT_IGL_ASSERT( min_grain_size >= 1 );
// UT_IGL_ASSERT( subscribe_ratio >= 0 );
//
// const size_t est_range_size( UTestimatedNumItems(range) );
//
@@ -3879,7 +3899,9 @@ namespace UT_Thread { inline int getNumProcessors() {
#include <limits>
#include <memory>
namespace igl { namespace FastWindingNumber {
namespace igl {
/// @private
namespace FastWindingNumber {
template<typename T> class UT_Array;
class v4uf;
@@ -3926,11 +3948,11 @@ struct Box {
}
SYS_FORCE_INLINE const T* operator[](const size_t axis) const noexcept {
UT_ASSERT_P(axis < NAXES);
UT_IGL_ASSERT_P(axis < NAXES);
return vals[axis];
}
SYS_FORCE_INLINE T* operator[](const size_t axis) noexcept {
UT_ASSERT_P(axis < NAXES);
UT_IGL_ASSERT_P(axis < NAXES);
return vals[axis];
}
@@ -4380,7 +4402,7 @@ private:
T diameter2 = box.diameter2();
return diameter2*SYSsqrt(diameter2);
}
UT_ASSERT_MSG(0, "BVH_Heuristic::MEDIAN_MAX_AXIS should be handled separately by caller!");
UT_IGL_ASSERT_MSG(0, "BVH_Heuristic::MEDIAN_MAX_AXIS should be handled separately by caller!");
return T(1);
}
@@ -4440,12 +4462,14 @@ using UT_BVH = UT::BVH<N>;
#include <igl/parallel_for.h>
#include "parallel_for.h"
#include <iostream>
#include <algorithm>
namespace igl { namespace FastWindingNumber {
namespace igl {
/// @private
namespace FastWindingNumber {
namespace HDK_Sample {
namespace UT {
@@ -4511,8 +4535,8 @@ struct ut_BoxCentre<UT_FixedVector<T,NAXES,INSTANTIATED>> {
template<typename BOX_TYPE,typename SRC_INT_TYPE,typename INT_TYPE>
inline INT_TYPE utExcludeNaNInfBoxIndices(const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE& nboxes) noexcept
{
constexpr INT_TYPE PARALLEL_THRESHOLD = 65536;
INT_TYPE ntasks = 1;
//constexpr INT_TYPE PARALLEL_THRESHOLD = 65536;
//INT_TYPE ntasks = 1;
//if (nboxes >= PARALLEL_THRESHOLD)
//{
// INT_TYPE nprocessors = UT_Thread::getNumProcessors();
@@ -4750,7 +4774,7 @@ inline void BVH<N>::traverseParallelHelper(
}
const INT_TYPE node_int = node.child[s];
if (Node::isInternal(node_int)) {
UT_ASSERT_MSG_P(node_int != Node::EMPTY, "Empty entries should have been excluded above.");
UT_IGL_ASSERT_MSG_P(node_int != Node::EMPTY, "Empty entries should have been excluded above.");
traverseParallelHelper(Node::getInternalNum(node_int), nodei, parallel_threshold, next_nodes[s], functors, &local_data[s]);
}
else {
@@ -4827,7 +4851,7 @@ inline void BVH<N>::traverseVectorHelper(
template<uint N>
template<typename SRC_INT_TYPE>
inline void BVH<N>::createTrivialIndices(SRC_INT_TYPE* indices, const INT_TYPE n) noexcept {
igl::parallel_for(n, [indices,n](INT_TYPE i) { indices[i] = i; }, 65536);
igl::parallel_for(n, [indices](INT_TYPE i) { indices[i] = i; }, 65536);
}
template<uint N>
@@ -4956,7 +4980,7 @@ inline void BVH<N>::initNode(UT_Array<Node>& nodes, Node &node, const Box<T,NAXE
++counted_parallel;
}
}
UT_ASSERT_P(counted_parallel == taski);
UT_IGL_ASSERT_P(counted_parallel == taski);
UT_Array<Node>& local_nodes = parallel_nodes[taski];
// Preallocate an overestimate of the number of nodes needed.
@@ -5150,7 +5174,7 @@ inline void BVH<N>::initNodeReorder(UT_Array<Node>& nodes, Node &node, const Box
// ++counted_parallel;
// }
// }
// UT_ASSERT_P(counted_parallel == taski);
// UT_IGL_ASSERT_P(counted_parallel == taski);
// UT_Array<Node>& local_nodes = parallel_nodes[taski];
// // Preallocate an overestimate of the number of nodes needed.
@@ -5273,7 +5297,7 @@ inline void BVH<N>::multiSplit(const Box<T,NAXES>& axes_minmax, const BOX_TYPE*
box = sub_boxes_unsorted[j];
}
}
UT_ASSERT_P(min_pointer);
UT_IGL_ASSERT_P(min_pointer);
sub_indices[i] = min_pointer;
sub_boxes[i] = box;
}
@@ -5297,7 +5321,7 @@ inline void BVH<N>::multiSplit(const Box<T,NAXES>& axes_minmax, const BOX_TYPE*
}
}
}
UT_ASSERT_MSG_P(split_choice != INT_TYPE(-1), "There should always be at least one that can be split!");
UT_IGL_ASSERT_MSG_P(split_choice != INT_TYPE(-1), "There should always be at least one that can be split!");
SRC_INT_TYPE* selected_start = sub_indices[split_choice];
SRC_INT_TYPE* selected_end = sub_indices[split_choice+1];
@@ -5330,10 +5354,10 @@ inline void BVH<N>::split(const Box<T,NAXES>& axes_minmax, const BOX_TYPE* boxes
split_indices = indices+1;
return;
}
UT_ASSERT_MSG_P(nboxes > 2, "Cases with less than 3 boxes should have already been handled!");
UT_IGL_ASSERT_MSG_P(nboxes > 2, "Cases with less than 3 boxes should have already been handled!");
if (H == BVH_Heuristic::MEDIAN_MAX_AXIS) {
UT_ASSERT_MSG(0, "FIXME: Implement this!!!");
UT_IGL_ASSERT_MSG(0, "FIXME: Implement this!!!");
}
constexpr INT_TYPE SMALL_LIMIT = 6;
@@ -5659,9 +5683,9 @@ inline void BVH<N>::split(const Box<T,NAXES>& axes_minmax, const BOX_TYPE* boxes
// Check which split is optimal, making sure that at least 1/MIN_FRACTION of all boxes are on each side.
const INT_TYPE min_count = nboxes/MIN_FRACTION;
UT_ASSERT_MSG_P(min_count > 0, "MID_LIMIT above should have been large enough that nboxes would be > MIN_FRACTION");
UT_IGL_ASSERT_MSG_P(min_count > 0, "MID_LIMIT above should have been large enough that nboxes would be > MIN_FRACTION");
const INT_TYPE max_count = ((MIN_FRACTION-1)*uint64(nboxes))/MIN_FRACTION;
UT_ASSERT_MSG_P(max_count < nboxes, "I'm not sure how this could happen mathematically, but it needs to be checked.");
UT_IGL_ASSERT_MSG_P(max_count < nboxes, "I'm not sure how this could happen mathematically, but it needs to be checked.");
T smallest_heuristic = std::numeric_limits<T>::infinity();
INT_TYPE split_index = -1;
for (INT_TYPE spliti = 0; spliti < NSPLITS; ++spliti) {
@@ -5796,7 +5820,7 @@ inline void BVH<N>::adjustParallelChildNodes(INT_TYPE nparallel, UT_Array<Node>&
++counted_parallel;
}
}
UT_ASSERT_P(counted_parallel == taski);
UT_IGL_ASSERT_P(counted_parallel == taski);
const UT_Array<Node>& local_nodes = parallel_nodes[counted_parallel];
INT_TYPE n = local_nodes.size();
@@ -6008,7 +6032,9 @@ void BVH<N>::debugDump() const {
#include <memory>
namespace igl { namespace FastWindingNumber {
namespace igl {
/// @private
namespace FastWindingNumber {
namespace HDK_Sample {
template<typename T>
@@ -6373,7 +6399,9 @@ private:
#include <stdlib.h>
namespace igl { namespace FastWindingNumber {
namespace igl {
/// @private
namespace FastWindingNumber {
// This needs to be here or else the warning suppression doesn't work because
// the templated calling code won't otherwise be compiled until after we've
@@ -6423,7 +6451,7 @@ inline void ut_ArrayImplFree(void *p)
#include <igl/parallel_for.h>
#include "parallel_for.h"
#include <type_traits>
#include <utility>
@@ -6440,7 +6468,9 @@ inline void ut_ArrayImplFree(void *p)
#define TAYLOR_SERIES_ORDER 2
namespace igl { namespace FastWindingNumber {
namespace igl {
/// @private
namespace FastWindingNumber {
namespace HDK_Sample {
@@ -6631,11 +6661,11 @@ inline void UT_SolidAngle<T,S>::init(
, myPositions(positions)
, myOrder(order)
{}
constexpr SYS_FORCE_INLINE bool pre(const int nodei, LocalData *data_for_parent) const
constexpr SYS_FORCE_INLINE bool pre(const int /*nodei*/, LocalData * /*data_for_parent*/) const
{
return true;
}
void item(const int itemi, const int parent_nodei, LocalData &data_for_parent) const
void item(const int itemi, const int /*parent_nodei*/, LocalData &data_for_parent) const
{
const UT_Vector3T<S> *const positions = myPositions;
const int *const cur_triangle_points = myTrianglePoints + 3*itemi;
@@ -6746,9 +6776,9 @@ inline void UT_SolidAngle<T,S>::init(
const UT_Vector3T<T> oab = b - a;
const UT_Vector3T<T> oac = c - a;
const UT_Vector3T<T> ocb = b - c;
UT_ASSERT_MSG_P(oac[i] > 0, "This should have been checked by the caller.");
UT_IGL_ASSERT_MSG_P(oac[i] > 0, "This should have been checked by the caller.");
const T t = oab[i]/oac[i];
UT_ASSERT_MSG_P(t >= 0 && t <= 1, "Either sorting must have gone wrong, or there are input NaNs.");
UT_IGL_ASSERT_MSG_P(t >= 0 && t <= 1, "Either sorting must have gone wrong, or there are input NaNs.");
const int j = (i==2) ? 0 : (i+1);
const int k = (j==2) ? 0 : (j+1);
@@ -6859,7 +6889,7 @@ inline void UT_SolidAngle<T,S>::init(
#endif
}
void post(const int nodei, const int parent_nodei, LocalData *data_for_parent, const int nchildren, const LocalData *child_data_array) const
void post(const int nodei, const int /*parent_nodei*/, LocalData *data_for_parent, const int nchildren, const LocalData *child_data_array) const
{
// NOTE: Although in the general case, data_for_parent may be null for the root call,
// this functor assumes that it's non-null, so the call below must pass a non-null pointer.
@@ -7139,9 +7169,9 @@ inline T UT_SolidAngle<T, S>::computeSolidAngle(const UT_Vector3T<T> &query_poin
: myBoxData(box_data)
, myQueryPoint(query_point)
, myAccuracyScale2(accuracy_scale2)
, myOrder(order)
, myPositions(positions)
, myTrianglePoints(triangle_points)
, myOrder(order)
{}
uint pre(const int nodei, T *data_for_parent) const
{
@@ -7227,7 +7257,7 @@ inline T UT_SolidAngle<T, S>::computeSolidAngle(const UT_Vector3T<T> &query_poin
return descend_bitmask;
}
void item(const int itemi, const int parent_nodei, T &data_for_parent) const
void item(const int itemi, const int /*parent_nodei*/, T &data_for_parent) const
{
const UT_Vector3T<S> *const positions = myPositions;
const int *const cur_triangle_points = myTrianglePoints + 3*itemi;
@@ -7237,7 +7267,7 @@ inline T UT_SolidAngle<T, S>::computeSolidAngle(const UT_Vector3T<T> &query_poin
data_for_parent = UTsignedSolidAngleTri(a, b, c, myQueryPoint);
}
SYS_FORCE_INLINE void post(const int nodei, const int parent_nodei, T *data_for_parent, const int nchildren, const T *child_data_array, const uint descend_bits) const
SYS_FORCE_INLINE void post(const int /*nodei*/, const int /*parent_nodei*/, T *data_for_parent, const int nchildren, const T *child_data_array, const uint descend_bits) const
{
T sum = (descend_bits&1) ? child_data_array[0] : 0;
for (int i = 1; i < nchildren; ++i)
@@ -7416,11 +7446,11 @@ inline void UT_SubtendedAngle<T,S>::init(
, myPositions(positions)
, myOrder(order)
{}
constexpr SYS_FORCE_INLINE bool pre(const int nodei, LocalData *data_for_parent) const
constexpr SYS_FORCE_INLINE bool pre(const int /*nodei*/, LocalData * /*data_for_parent*/) const
{
return true;
}
void item(const int itemi, const int parent_nodei, LocalData &data_for_parent) const
void item(const int itemi, const int /*parent_nodei*/, LocalData &data_for_parent) const
{
const UT_Vector2T<S> *const positions = myPositions;
const int *const cur_segment_points = mySegmentPoints + 2*itemi;
@@ -7486,7 +7516,7 @@ inline void UT_SubtendedAngle<T,S>::init(
#endif
}
void post(const int nodei, const int parent_nodei, LocalData *data_for_parent, const int nchildren, const LocalData *child_data_array) const
void post(const int nodei, const int /*parent_nodei*/, LocalData *data_for_parent, const int nchildren, const LocalData *child_data_array) const
{
// NOTE: Although in the general case, data_for_parent may be null for the root call,
// this functor assumes that it's non-null, so the call below must pass a non-null pointer.
@@ -7768,7 +7798,7 @@ inline T UT_SubtendedAngle<T, S>::computeAngle(const UT_Vector2T<T> &query_point
return descend_bitmask;
}
void item(const int itemi, const int parent_nodei, T &data_for_parent) const
void item(const int itemi, const int /*parent_nodei*/, T &data_for_parent) const
{
const UT_Vector2T<S> *const positions = myPositions;
const int *const cur_segment_points = mySegmentPoints + 2*itemi;
@@ -7777,7 +7807,7 @@ inline T UT_SubtendedAngle<T, S>::computeAngle(const UT_Vector2T<T> &query_point
data_for_parent = UTsignedAngleSegment(a, b, myQueryPoint);
}
SYS_FORCE_INLINE void post(const int nodei, const int parent_nodei, T *data_for_parent, const int nchildren, const T *child_data_array, const uint descend_bits) const
SYS_FORCE_INLINE void post(const int /*nodei*/, const int /*parent_nodei*/, T *data_for_parent, const int nchildren, const T *child_data_array, const uint descend_bits) const
{
T sum = (descend_bits&1) ? child_data_array[0] : 0;
for (int i = 1; i < nchildren; ++i)
+1 -1
View File
@@ -10,7 +10,7 @@
namespace igl
{
/// File encoding types for writing files.
enum class FileEncoding {
Binary,
Ascii
+2 -1
View File
@@ -32,7 +32,7 @@ namespace igl {
pos_type seekoff(
off_type off,
std::ios_base::seekdir dir,
std::ios_base::openmode which) override
std::ios_base::openmode /*which*/) override
{
if (dir == std::ios_base::cur)
{
@@ -50,6 +50,7 @@ namespace igl {
}
};
/// Class to convert a FILE * to an std::istream
struct FileMemoryStream : virtual FileMemoryBuffer, public std::istream
{
FileMemoryStream( char const *first_elem, size_t size)
+4 -4
View File
@@ -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, ...
+49 -45
View File
@@ -11,35 +11,24 @@
#include <Eigen/Core>
#include <vector>
#include <igl/igl_inline.h>
#include "igl_inline.h"
// This file violates many of the libigl style guidelines.
namespace igl
{
// HalfEdgeIterator - Fake halfedge for fast and easy navigation
// on triangle meshes with vertex_triangle_adjacency and
// triangle_triangle adjacency
//
// Note: this is different to classical Half Edge data structure.
// Instead, it follows cell-tuple in [Brisson, 1989]
// "Representing geometric structures in d dimensions: topology and order."
// This class can achieve local navigation similar to half edge in OpenMesh
// But the logic behind each atom operation is different.
// So this should be more properly called TriangleTupleIterator.
//
// Each tuple contains information on (face, edge, vertex)
// and encoded by (face, edge \in {0,1,2}, bool reverse)
//
// Inputs:
// F #F by 3 list of "faces"
// FF #F by 3 list of triangle-triangle adjacency.
// FFi #F by 3 list of FF inverse. For FF and FFi, refer to
// "triangle_triangle_adjacency.h"
// Usages:
// FlipF/E/V changes solely one actual face/edge/vertex resp.
// NextFE iterates through one-ring of a vertex robustly.
//
/// Fake halfedge for fast and easy navigation
/// on triangle meshes with vertex_triangle_adjacency and
/// triangle_triangle adjacency
///
/// Note: this is different to classical Half Edge data structure.
/// Instead, it follows cell-tuple in [Brisson, 1989]
/// "Representing geometric structures in d dimensions: topology and order."
/// This class can achieve local navigation similar to half edge in OpenMesh
/// But the logic behind each atom operation is different.
/// So this should be more properly called TriangleTupleIterator.
///
/// Each tuple contains information on (face, edge, vertex)
/// and encoded by (face, edge \in {0,1,2}, bool reverse)
template <
typename DerivedF,
typename DerivedFF,
@@ -47,7 +36,15 @@ 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::MatrixBase<DerivedF>& _F,
const Eigen::MatrixBase<DerivedFF>& _FF,
@@ -57,41 +54,48 @@ namespace igl
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:
+13 -11
View File
@@ -11,19 +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 (not used)
// 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;
float u,v;
// parametric distance so that
// pos = origin + t * dir
float t;
/// 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
View File
@@ -0,0 +1,9 @@
// https://stackoverflow.com/a/985807/148668
#include <cassert>
#ifndef IGL_ASSERT
#ifdef NDEBUG
#define IGL_ASSERT(x) do { (void)sizeof(x);} while (0)
#else
#define IGL_ASSERT(x) assert(x)
#endif
#endif
+7 -9
View File
@@ -8,10 +8,8 @@
#ifndef IGL_INDEXCOMPARISON_H
#define IGL_INDEXCOMPARISON_H
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) {}
@@ -22,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) {}
@@ -33,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) {}
@@ -44,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) :
@@ -67,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) {}
@@ -91,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) {}
+34 -25
View File
@@ -1,33 +1,42 @@
#ifndef IGL_LINSPACED_H
#define IGL_LINSPACED_H
#include <Eigen/Core>
// This function is not intended to be a permanent function of libigl. Rather
// it is a "drop-in" workaround for documented bug in Eigen:
// http://eigen.tuxfamily.org/bz/show_bug.cgi?id=1383
//
// Replace:
//
// Eigen::VectorXi::LinSpaced(size,low,high);
//
// With:
//
// igl::LinSpaced<Eigen::VectorXi>(size,low,high);
//
// Specifcally, this version will _always_ return an empty vector if size==0,
// regardless of the values for low and high. If size != 0, then this simply
// returns the result of Eigen::Derived::LinSpaced.
//
// Until this bug is fixed, we should also avoid calls to the member function
// `.setLinSpaced`. This means replacing:
//
// a.setLinSpaced(size,low,high);
//
// with
//
// a = igl::LinSpaced<decltype(a) >(size,low,high);
//
/// @file LinSpaced.h
///
/// This function is not intended to be a permanent function of libigl. Rather
/// it is a "drop-in" workaround for documented bug in Eigen:
/// http://eigen.tuxfamily.org/bz/show_bug.cgi?id=1383
///
/// Replace:
///
/// Eigen::VectorXi::LinSpaced(size,low,high);
///
/// With:
///
/// igl::LinSpaced<Eigen::VectorXi>(size,low,high);
///
/// Specifcally, this version will _always_ return an empty vector if size==0,
/// regardless of the values for low and high. If size != 0, then this simply
/// returns the result of Eigen::Derived::LinSpaced.
///
/// Until this bug is fixed, we should also avoid calls to the member function
/// `.setLinSpaced`. This means replacing:
///
/// a.setLinSpaced(size,low,high);
///
/// with
///
/// a = igl::LinSpaced<decltype(a) >(size,low,high);
///
namespace igl
{
/// Replacement for Eigen::DenseBase::LinSpaced
/// @param[in] size number of elements
/// @param[in] low first element
/// @param[in] high last element
/// @return vector of size elements linearly spaced between low and
///
/// \fileinfo
template <typename Derived>
//inline typename Eigen::DenseBase< Derived >::RandomAccessLinSpacedReturnType
inline Derived LinSpaced(
+2 -3
View File
@@ -9,10 +9,9 @@
#define IGL_MAPPINGENERGYTYPE_H
namespace igl
{
// Energy Types used for Parameterization/Mapping.
// Refer to SLIM [Rabinovich et al. 2017] for more details
/// Energy Types used for Parameterization/Mapping.
/// Refer to SLIM [Rabinovich et al. 2017] for more details
// Todo: Integrate with ARAPEnergyType
enum MappingEnergyType
{
ARAP = 0,
+7
View File
@@ -9,13 +9,20 @@
#define IGL_MESH_BOOLEAN_TYPE_H
namespace igl
{
/// Boolean operation types
enum MeshBooleanType
{
/// A B
MESH_BOOLEAN_TYPE_UNION = 0,
/// A ∩ B
MESH_BOOLEAN_TYPE_INTERSECT = 1,
/// A \ B
MESH_BOOLEAN_TYPE_MINUS = 2,
/// A ⊕ B
MESH_BOOLEAN_TYPE_XOR = 3,
/// Resolve intersections without removing any non-coplanar faces
MESH_BOOLEAN_TYPE_RESOLVE = 4,
/// Total number of Boolean options
NUM_MESH_BOOLEAN_TYPES = 5
};
};
+5 -3
View File
@@ -18,8 +18,8 @@
namespace igl {
// Class for loading information from .msh file
// depends only on c++stl library
/// Class for loading information from .msh file
/// depends only on c++stl library
class MshLoader {
public:
@@ -60,6 +60,8 @@ class MshLoader {
// 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:
@@ -187,4 +189,4 @@ class MshLoader {
# include "MshLoader.cpp"
#endif
#endif //IGL_MSH_LOADER_H
#endif //IGL_MSH_LOADER_H
-4
View File
@@ -105,7 +105,6 @@ IGL_INLINE void igl::MshSaver::save_elements(const IndexVector& elements,
if (m_num_elements > 0) {
//int elem_type = el_type;
int num_elems = m_num_elements;
//int tags = 0;
if (!m_binary) {
size_t el_ptr=0;
@@ -213,7 +212,6 @@ IGL_INLINE void igl::MshSaver::save_vector_field(const std::string& fieldname, c
fout << "3" << std::endl; // 3-component vector field.
fout << m_num_nodes << std::endl; // number of nodes
const Float zero = 0.0;
if (m_binary) {
for (size_t i=0; i<m_num_nodes; i++) {
int node_idx = i+1;
@@ -275,7 +273,6 @@ IGL_INLINE void igl::MshSaver::save_elem_vector_field(const std::string& fieldna
fout << "3" << std::endl; // 3-component vector field.
fout << m_num_elements << std::endl; // number of elements
const Float zero = 0.0;
if (m_binary) {
for (size_t i=0; i<m_num_elements; ++i) {
int elem_idx = i+1;
@@ -310,7 +307,6 @@ IGL_INLINE void igl::MshSaver::save_elem_tensor_field(const std::string& fieldna
fout << "9" << std::endl; // 9-component tensor field.
fout << m_num_elements << std::endl; // number of elements
const Float zero = 0.0;
if (m_binary) {
for (size_t i=0; i<m_num_elements; i++) {
+6 -3
View File
@@ -16,9 +16,9 @@
namespace igl {
// Class for dumping information to .msh file
// depends only on c++stl library
// current implementation works only with 3D information
/// 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;
@@ -30,6 +30,9 @@ class MshSaver {
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();
+5 -4
View File
@@ -10,14 +10,15 @@
namespace igl
{
// PER_VERTEX_NORMALS Normals computed per vertex based on incident faces
// PER_FACE_NORMALS Normals computed per face
// PER_CORNER_NORMALS Normals computed per corner (aka wedge) based on
// incident faces without sharp edge
/// Type of mesh normal computation method
enum NormalType
{
/// Normals computed per vertex based on incident faces
PER_VERTEX_NORMALS,
/// Normals computed per face
PER_FACE_NORMALS,
/// Normals computed per corner (aka wedge) based on incident faces without
/// sharp edge
PER_CORNER_NORMALS
};
# define NUM_NORMAL_TYPE 3
+3 -3
View File
@@ -9,9 +9,9 @@
#define IGL_ONE_H
namespace igl
{
// Often one needs a reference to a dummy variable containing one as its
// value, for example when using AntTweakBar's
// TwSetParam( "3D View", "opened", TW_PARAM_INT32, 1, &INT_ONE);
/// Often one needs a reference to a dummy variable containing one as its
/// value, for example when using AntTweakBar's
/// TwSetParam( "3D View", "opened", TW_PARAM_INT32, 1, &INT_ONE);
const char CHAR_ONE = 1;
const int INT_ONE = 1;
const unsigned int UNSIGNED_INT_ONE = 1;
+28
View File
@@ -0,0 +1,28 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2019 Qingnan Zhou <qnzhou@gmail.com>
// 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/.
#pragma once
#ifndef IGL_ORIENTATION_H
#define IGL_ORIENTATION_H
#include "igl_inline.h"
#include <Eigen/Core>
namespace igl {
/// Types of orientations and other predicate results.
///
/// \fileinfo
enum class Orientation {
POSITIVE=1, INSIDE=1,
NEGATIVE=-1, OUTSIDE=-1,
COLLINEAR=0, COPLANAR=0, COCIRCULAR=0, COSPHERICAL=0, DEGENERATE=0
};
}
#endif
+2
View File
@@ -11,8 +11,10 @@ namespace igl
{
// Use standard mathematical constants' M_PI if available
#ifdef M_PI
/// π
constexpr double PI = M_PI;
#else
/// π
constexpr double PI = 3.1415926535897932384626433832795;
#endif
}
+95
View File
@@ -0,0 +1,95 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2024 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_PLAINMATRIX_H
#define IGL_PLAINMATRIX_H
#include <Eigen/Core>
#include <type_traits>
#include <Eigen/Dense>
// Define void_t for compatibility if it's not in the standard library (C++11 and later)
#if __cplusplus < 201703L
namespace std {
template <typename... Ts>
using void_t = void;
}
#endif
#ifndef IGL_DEFAULT_MAJORING
#define IGL_DEFAULT_MAJORING Eigen::ColMajor
#endif
namespace igl
{
template <typename Derived, int Rows, int Cols, int Options>
struct PlainMatrixHelper {
using Type = Eigen::Matrix<typename Derived::Scalar,Rows,Cols,((Rows == 1 && Cols != 1) ? Eigen::RowMajor : ((Cols == 1 && Rows != 1) ? Eigen::ColMajor : Options))>;
};
template <typename Derived, typename = void>
struct get_options {
static constexpr int value = IGL_DEFAULT_MAJORING;
};
template <typename Derived>
struct get_options<Derived, std::void_t<decltype(Derived::Options)>> {
static constexpr int value = Derived::Options;
};
/// Some libigl implementations would (still do?) use a pattern like:
///
/// template <typename DerivedA>
/// void foo(const Eigen::MatrixBase<DerivedA>& A)
/// {
/// DerivedA B;
/// igl::unique_rows(A,true,B);
/// }
///
/// If `DerivedA` is `Eigen::Matrix`, then this may compile, but `DerivedA` might be
/// from a Eigen::Map or Eigen::Ref and fail to compile due to missing
/// construtor.
///
/// Even worse, the code above will work if `DerivedA` has dynamic rows, but will
/// throw a runtime error if `DerivedA` has fixed number of rows.
///
/// Instead it's better to declare `B` as a `Eigen::Matrix`
///
/// Eigen::Matrix<typename DerivedA::Scalar,Eigen::Dynamic,DerivedA::ColsAtCompileTime,DerivedA::Options> B;
///
/// Using `Eigen::Dynamic` for dimensions that may not be known at compile
/// time (or may be different from A).
///
/// `igl::PlainMatrix` is just a helper to make this easier. So in this case
/// we could write:
///
/// igl::PlainMatrix<DerivedA,Eigen::Dynamic> B;
///
/// IIUC, if the code in question looks like:
///
/// template <typename DerivedC>
/// void foo(Eigen::PlainObjectBase<DerivedC>& C)
/// {
/// DerivedC B;
/// …
/// C.resize(not_known_at_compile_time,also_not_known_at_compile_time);
/// }
///
/// Then it's probably fine. If C can be resized to different sizes, then
/// `DerivedC` should be `Eigen::Matrix`-like .
// Helper to check if `Options` exists in Derived
// Modify PlainMatrix to use get_options
template <typename Derived,
int Rows = Derived::RowsAtCompileTime,
int Cols = Derived::ColsAtCompileTime,
int Options = get_options<Derived>::value>
using PlainMatrix = typename PlainMatrixHelper<Derived, Rows, Cols, Options>::Type;
}
#endif
+36
View File
@@ -0,0 +1,36 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2024 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_PLAINVECTOR_H
#define IGL_PLAINVECTOR_H
#include <Eigen/Core>
#include "PlainMatrix.h"
namespace igl
{
// PlainVectorHelper to determine correct matrix type based on Derived and Size
template <typename Derived, int Size, int Options>
struct PlainVectorHelper {
// Conditional Type: Column vector if is_column_vector is true, otherwise row vector
using Type = Eigen::Matrix<
typename Derived::Scalar,
(Derived::ColsAtCompileTime == 1 && Derived::RowsAtCompileTime != 1) ? Size : 1,
(Derived::ColsAtCompileTime == 1 && Derived::RowsAtCompileTime != 1) ? 1 : Size,
Options>;
};
/// \see PlainMatrix
template <
typename Derived,
int Size = (Derived::ColsAtCompileTime == 1 && Derived::RowsAtCompileTime != 1) ? Derived::RowsAtCompileTime : Derived::ColsAtCompileTime,
int Options = get_options<Derived>::value>
using PlainVector = typename PlainVectorHelper<Derived, Size, Options>::Type;
}
#endif
+9 -1
View File
@@ -35,9 +35,17 @@
#else
/// Bold red colored text
/// @param[in] X text to color
/// @returns colored text as "stream"
/// #### Example:
///
/// \code{cpp}
/// std::cout<<REDRUM("File "<<filename<<" not found.")<<std::endl;
/// \endcode
#define REDRUM(X) "\e[1m\e[31m"<<X<<"\e[m"
// Bold Red, etc.
#define NORUM(X) ""<<X<<""
#define REDRUM(X) "\e[1m\e[31m"<<X<<"\e[m"
#define GREENRUM(X) "\e[1m\e[32m"<<X<<"\e[m"
#define YELLOWRUM(X) "\e[1m\e[33m"<<X<<"\e[m"
#define BLUERUM(X) "\e[1m\e[34m"<<X<<"\e[m"
+16 -5
View File
@@ -7,12 +7,23 @@
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_STR_H
#define IGL_STR_H
// http://stackoverflow.com/a/2433143/148668
#include <string>
#include <sstream>
// Suppose you have a function:
// void func(std::string c);
// Then you can write:
// func(STR("foo"<<1<<"bar"));
/// Convert a stream of things to std:;string
///
/// Suppose you have a function:
/// \code{cpp}
/// void func(std::string s);
/// \endcode
/// Then you can write:
/// \code{cpp}
/// func(C_STR("foo"<<1<<"bar"));
/// \endcode
/// which is equivalent to:
/// \code{cpp}
/// func("foo1bar");
/// \endcode
///
// http://stackoverflow.com/a/2433143/148668
#define STR(X) static_cast<std::ostringstream&>(std::ostringstream().flush() << X).str()
#endif
@@ -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
+5 -3
View File
@@ -9,14 +9,16 @@
#define IGL_SOLVER_STATUS_H
namespace igl
{
/// Solver status type used by min_quad_with_fixed
enum SolverStatus
{
// Good
// Good. Solver declared convergence
SOLVER_STATUS_CONVERGED = 0,
// OK
// OK. Solver reached max iterations
SOLVER_STATUS_MAX_ITER = 1,
// Bad
// Bad. Solver reported failure
SOLVER_STATUS_ERROR = 2,
// Total number of solver types
NUM_SOLVER_STATUSES = 3,
};
};
+15 -2
View File
@@ -14,16 +14,23 @@
namespace igl
{
// Templates:
// T should be a matrix that implements .size(), and operator(int i)
/// 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
@@ -41,6 +48,9 @@ namespace igl
// All characters the same, comes done to length
return this->data.size()<that.data.size();
};
/// 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())
@@ -56,6 +66,9 @@ namespace igl
}
return true;
};
/// 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);
+231
View File
@@ -0,0 +1,231 @@
// 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/.
#include "SphereMeshWedge.h"
#include "round_cone_signed_distance.h"
#include "sign.h"
#include <Eigen/QR>
#include <Eigen/Geometry>
template <typename Scalar>
IGL_INLINE igl::SphereMeshWedge<Scalar>::SphereMeshWedge(
const RowVector3S & V0,
const RowVector3S & V1,
const RowVector3S & V2,
const Scalar r0,
const Scalar r1,
const Scalar r2)
{
// Internal copy
V.row(0) = V0;
V.row(1) = V1;
V.row(2) = V2;
r(0) = r0;
r(1) = r1;
r(2) = r2;
flavor = FULL;
// By default use full
EV.row(0) = V.row(2) - V.row(1);
EV.row(1) = V.row(0) - V.row(2);
EV.row(2) = V.row(1) - V.row(0);
l = EV.rowwise().norm();
l2 = l.array().square();
rr << r(1) - r(2), r(2) - r(0), r(0) - r(1);
a2 = l2.array() - rr.array().square();
il2 = 1.0/l2.array();
/////////////////////////////////////////////
/// BIG_VERTEX ?
/////////////////////////////////////////////
{
r.maxCoeff(&max_i);
int j = (max_i+1)%3;
int k = (max_i+2)%3;
if((l(k) + r(j) < r(max_i)) && (l(j) + r(k) < r(max_i)))
{
flavor = BIG_VERTEX;
}
}
/////////////////////////////////////////////
/// BIG_EDGE ?
/////////////////////////////////////////////
if(flavor == FULL)
{
// Case where one edge's roundCone containes the others
for(int e = 0;e<3;e++)
{
const int i = (e+1)%3;
const int j = (e+2)%3;
const int k = (e+3)%3;
const Scalar s =
igl::round_cone_signed_distance(V.row(k),V.row(i),V.row(j),r(i),r(j));
if(-s > r(k))
{
flavor = BIG_EDGE;
max_i = i;
break;
}
}
}
if(flavor == FULL && !compute_planes())
{
flavor = NO_TRIANGLE;
}
}
template <typename Scalar>
IGL_INLINE Scalar igl::SphereMeshWedge<Scalar>::operator()(const RowVector3S & p) const
{
if(flavor == BIG_VERTEX)
{
// Case 0: Vertex i
return (p - V.row(max_i)).norm() - r(max_i);
}
if(flavor == BIG_EDGE)
{
const int i = max_i;
const int j = (i+1)%3;
// Case 1: Edge e
return this->round_cone_signed_distance(p,i,j);
}
Scalar s = std::numeric_limits<Scalar>::infinity();
if(flavor == FULL)
{
// This is possibly the bottleneck and could be turned into precomputed
// plane equations.
// signed distance to triangle plane (this is immediately recomputed later in
// sdSkewedExtrudedTriangle...)
const auto plane_sdf = [](
const RowVector3S & p,
const Eigen::RowVector4d & plane)
{
return plane.head<3>().dot(p) + plane(3);
};
Scalar d0 = plane_sdf(p, planes.row(0));
Scalar planes_s = -std::abs(d0);
// Reflect if necessary so that q is always on negative side of plane
RowVector3S q = p - (d0 - planes_s) * planes.row(0).template head<3>();
// Other planes (for negative side slab, by symmetry)
for(int i = 1;i<planes.rows();i++)
{
planes_s = std::max(planes_s,plane_sdf(q, planes.row(i)));
}
// This produces correct interior distance
if(planes_s <= 0)
{
s = std::min(s,planes_s);
}else
{
const auto & nor = planes.row(1).template head<3>();
const RowVector3S q0 = q - T.row(0);
const RowVector3S q1 = q - T.row(1);
const RowVector3S q2 = q - T.row(2);
if(!(sign(C.row(0).dot(q0)) +
sign(C.row(1).dot(q1)) +
sign(C.row(2).dot(q2))<2.0))
{
s = std::min(s,planes_s);
}
}
//s = std::min(s,sdSkewedExtrudedTriangle(q,V,T));
//s = std::min(s,sdSkewedExtrudedTriangle(p,B,V));
}
assert(flavor == FULL || flavor == NO_TRIANGLE);
for(int e = 0;e<3;e++)
{
const int i = (e+1)%3;
const int j = (e+2)%3;
s = std::min(s,this->round_cone_signed_distance(p,i,j));
}
return s;
}
template <typename Scalar>
IGL_INLINE bool igl::SphereMeshWedge<Scalar>::compute_planes()
{
// Non-degenerate case
const RowVector3S & a = V.row(0);
const RowVector3S & b = V.row(1);
const RowVector3S & c = V.row(2);
const Scalar & ra = r(0);
const Scalar & rb = r(1);
const Scalar & rc = r(2);
Eigen::Matrix<Scalar,2,3,Eigen::RowMajor> A;
A<<
b-a,
c-a;
const Eigen::Vector2d d(rb-ra,rc-ra);
const RowVector3S N = (A.row(0).cross(A.row(1))).normalized();
//const Eigen::CompleteOrthogonalDecomposition<decltype(A)> cod(A);
const RowVector3S n0 = A.completeOrthogonalDecomposition().solve(d);
const Scalar qA = N.squaredNorm();
// qB is zeros by construction. We could delete all terms involving qB
// It's not even clear if keeping them would lead to more accurate results.
const Scalar qB = 2 * N.dot(n0);
const Scalar qC = n0.squaredNorm() - 1;
const Scalar qD = qB*qB - 4*qA*qC;
if(qD<0) { return false; }
Scalar t_sol_1 = (-qB + std::sqrt(qD)) / (2*qA);
RowVector3S n1 = -(t_sol_1 * N + n0);
T = V + r * n1;
const auto plane_equation = [](
const RowVector3S & a,
const RowVector3S & b,
const RowVector3S & c)->Eigen::RowVector4d
{
RowVector3S n = (b-a).cross(c-a).normalized();
n.normalize();
Scalar d = -n.dot(a);
return Eigen::RowVector4d(n(0),n(1),n(2),d);
};
planes.row(0) = plane_equation(V.row(0),V.row(1),V.row(2));
planes.row(1) = plane_equation(T.row(2),T.row(1),T.row(0));
planes.row(2) = plane_equation(V.row(1),V.row(0),T.row(0));
planes.row(3) = plane_equation(V.row(2),V.row(1),T.row(1));
planes.row(4) = plane_equation(V.row(0),V.row(2),T.row(2));
// Determine if the closest point is on the face.
const RowVector3S v10 = T.row(1) - T.row(0);
const RowVector3S v21 = T.row(2) - T.row(1);
const RowVector3S v02 = T.row(0) - T.row(2);
const auto & nor = planes.row(1).template head<3>();
const RowVector3S c10 = v10.cross(nor);
const RowVector3S c21 = v21.cross(nor);
const RowVector3S c02 = v02.cross(nor);
C<<c10,c21,c02;
return true;
}
template <typename Scalar>
IGL_INLINE Scalar igl::SphereMeshWedge<Scalar>::round_cone_signed_distance(const RowVector3S & p, const int i, const int j) const
{
const int e = (j+1)%3;
return igl::round_cone_signed_distance(
p, V.row(i), r(i), r(j), EV.row(e), l2(e), rr(e), a2(e), il2(e));
}
#ifdef IGL_STATIC_LIBRARY
/// Explicit template instantiation
template class igl::SphereMeshWedge<double>;
#endif
+87
View File
@@ -0,0 +1,87 @@
// 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_SPHERE_MESH_WEDGE_H
#define IGL_SPHERE_MESH_WEDGE_H
#include "igl_inline.h"
#include <Eigen/Core>
namespace igl
{
/// A class to compute the signed distance to a "Sphere-Mesh Wedge" as seen in
/// variable radius offset surfaces or Sphere-Meshes. Each wedge is defined
/// by three vertices and three radii, one at each vertex. The wedge is
/// the union of all spheres at points on the triangle with radius linearly
/// interpolated. See, e.g., "Sphere-Meshes for Real-Time Hand Modeling and
/// Tracking" or "A Multilinear Model for Bidirectional Craniofacial
/// Reconstruction" or "Sphere-Meshes: Shape Approximation using Spherical
/// Quadric Error Metrics" or "Variable-Radius Offset Surface Approximation on
/// the GPU".
///
template <typename Scalar>
class SphereMeshWedge
{
public:
using RowVector3S = Eigen::Matrix<Scalar, 1, 3>;
// Fields
enum
{
BIG_VERTEX = 0,
BIG_EDGE = 1,
NO_TRIANGLE = 2,
FULL = 3
} flavor;
Eigen::Matrix<Scalar,3,3,Eigen::RowMajor> V;
Eigen::Matrix<Scalar,3,1> r;
Eigen::Matrix<Scalar,3,3,Eigen::RowMajor> EV;
Eigen::Matrix<Scalar,3,1> l,l2,rr,a2,il2;
int max_i;
Eigen::Matrix<Scalar,5,4,Eigen::RowMajor> planes;
Eigen::Matrix<Scalar,3,3,Eigen::RowMajor> T;
Eigen::Matrix<Scalar,3,3,Eigen::RowMajor> C;
SphereMeshWedge(){}
/// Constructor that takes three vertices and three radii
///
/// @param V0 first vertex position
/// @param V1 second vertex position
/// @param V2 third vertex position
/// @param r0 radius at first vertex
/// @param r1 radius at second vertex
/// @param r2 radius at third vertex
IGL_INLINE SphereMeshWedge(
const RowVector3S & V0,
const RowVector3S & V1,
const RowVector3S & V2,
const Scalar r0,
const Scalar r1,
const Scalar r2);
/// @param[in] p 3-vector query point
/// @return signed distance to the wedge at point p
IGL_INLINE Scalar operator()(const RowVector3S & p) const;
private:
/// Precompute planes used for determining bounded signed to the skewed
/// triangular slab portion.
///
/// @return true if planes are well defined (false implies this slab has
/// no contribution).
IGL_INLINE bool compute_planes();
/// Compute the signed distance to the wedge at a point p for the edge
/// (i,j)
///
/// @param[in] p 3-vector query point
/// @param[in] i index of first vertex (0,1,2)
/// @param[in] j index of second vertex (0,1,2)
IGL_INLINE Scalar round_cone_signed_distance(const RowVector3S & p, const int i, const int j) const;
};
}
#ifndef IGL_STATIC_LIBRARY
#include "SphereMeshWedge.cpp"
#endif
#endif
+21 -12
View File
@@ -22,13 +22,15 @@
#include <sys/time.h>
#endif
#include <cstddef>
#include <cstdint>
namespace igl
{
/// Simple timer class
class Timer
{
public:
// default constructor
/// default constructor
Timer():
stopped(0),
#ifdef WIN32
@@ -64,10 +66,13 @@ namespace igl
}
#ifdef __APPLE__
//Raw mach_absolute_times going in, difference in seconds out
double subtractTimes( uint64_t endTime, uint64_t startTime )
/// Raw mach_absolute_times going in, difference in seconds out
/// @param[in] endTime end time
/// @param[in] startTime start time
/// @return time
double subtractTimes( std::uint64_t endTime, std::uint64_t startTime )
{
uint64_t difference = endTime - startTime;
std::uint64_t difference = endTime - startTime;
static double conversion = 0.0;
if( conversion == 0.0 )
@@ -84,7 +89,7 @@ namespace igl
}
#endif
// start timer
/// start timer
void start()
{
stopped = 0; // reset stop flag
@@ -98,7 +103,7 @@ namespace igl
}
// stop the timer
/// stop the timer
void stop()
{
stopped = 1; // set timer stopped flag
@@ -112,23 +117,27 @@ namespace igl
#endif
}
// get elapsed time in second
/// get elapsed time in second
/// @return time in seconds
double getElapsedTime()
{
return this->getElapsedTimeInSec();
}
// get elapsed time in second (same as getElapsedTime)
/// get elapsed time in second (same as getElapsedTime)
/// @return time
double getElapsedTimeInSec()
{
return this->getElapsedTimeInMicroSec() * 0.000001;
}
// get elapsed time in milli-second
/// get elapsed time in milli-second
/// @return time
double getElapsedTimeInMilliSec()
{
return this->getElapsedTimeInMicroSec() * 0.001;
}
// get elapsed time in micro-second
/// get elapsed time in micro-second
/// @return time
double getElapsedTimeInMicroSec()
{
double startTimeInMicroSec = 0;
@@ -167,8 +176,8 @@ namespace igl
LARGE_INTEGER startCount;
LARGE_INTEGER endCount;
#elif __APPLE__
uint64_t startCount;
uint64_t endCount;
std::uint64_t startCount;
std::uint64_t endCount;
#else
timeval startCount;
timeval endCount;
+1
View File
@@ -10,6 +10,7 @@
namespace igl
{
/// @private
// Simple Viewport class for an opengl context. Handles reshaping and mouse.
struct Viewport
{
+96 -95
View File
@@ -13,19 +13,24 @@
#ifndef IGL_WINDINGNUMBERAABB_H
#define IGL_WINDINGNUMBERAABB_H
#include "WindingNumberTree.h"
#include "PlainMatrix.h"
namespace igl
{
/// Class for building an AABB tree to implement the divide and conquer
/// algorithm described in [Jacobson et al. 2013].
template <
typename Point,
typename DerivedV,
typename DerivedF >
class WindingNumberAABB : public WindingNumberTree<Point,DerivedV,DerivedF>
typename Scalar,
typename Index>
class WindingNumberAABB : public WindingNumberTree<Scalar,Index>
{
protected:
// WindingNumberTree defines Point
using Point = typename WindingNumberTree<Scalar,Index>::Point;
using MatrixXF = typename WindingNumberTree<Scalar,Index>::MatrixXF;
Point min_corner;
Point max_corner;
typename DerivedV::Scalar total_positive_area;
Scalar total_positive_area;
public:
enum SplitMethod
{
@@ -35,16 +40,25 @@ namespace igl
} split_method;
public:
inline WindingNumberAABB():
total_positive_area(std::numeric_limits<typename DerivedV::Scalar>::infinity()),
total_positive_area(std::numeric_limits<Scalar>::infinity()),
split_method(MEDIAN_ON_LONGEST_AXIS)
{}
/// Constructor
///
/// @param[in] V #V by 3 list of vertex positions
/// @param[in] F #F by 3 list of triangle indices into V
template <typename DerivedV, typename DerivedF>
inline WindingNumberAABB(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F);
inline WindingNumberAABB(
const WindingNumberTree<Point,DerivedV,DerivedF> & parent,
const Eigen::MatrixBase<DerivedF> & F);
// Initialize some things
const WindingNumberTree<Scalar,Index> & parent,
const typename WindingNumberTree<Scalar,Index>::MatrixXF & F);
/// Initialize the hierarchy to a given mesh
///
/// @param[in] V #V by 3 list of vertex positions
/// @param[in] F #F by 3 list of triangle indices into V
template <typename DerivedV, typename DerivedF>
inline void set_mesh(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F);
@@ -53,8 +67,8 @@ namespace igl
inline virtual void grow();
// Compute min and max corners
inline void compute_min_max_corners();
inline typename DerivedV::Scalar max_abs_winding_number(const Point & p) const;
inline typename DerivedV::Scalar max_simple_abs_winding_number(const Point & p) const;
inline Scalar max_abs_winding_number(const Point & p) const;
inline Scalar max_simple_abs_winding_number(const Point & p) const;
};
}
@@ -77,70 +91,73 @@ 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 +165,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 =
-std::numeric_limits<Scalar>::infinity();
for(int d = 0;d<min_corner.size();d++)
{
if( (max_corner[d] - min_corner[d]) > max_len )
@@ -159,13 +176,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 +199,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++)
std::vector<int> id( (this->F).rows());
for(int i = 0;i<(this->F).rows();i++)
{
if(BC(i,max_d) <= split_value)
{
@@ -201,19 +218,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 +239,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,39 +267,38 @@ 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
for(int d = 0;d<min_corner.size();d++)
{
min_corner[d] = numeric_limits<typename Point::Scalar>::infinity();
max_corner[d] = -numeric_limits<typename Point::Scalar>::infinity();
min_corner[d] = std::numeric_limits<typename Point::Scalar>::infinity();
max_corner[d] = -std::numeric_limits<typename Point::Scalar>::infinity();
}
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,32 +309,29 @@ 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 std::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 std::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;
using namespace Eigen;
// Only valid if not inside
if(inside(p))
{
return numeric_limits<typename DerivedV::Scalar>::infinity();
return std::numeric_limits<Scalar>::infinity();
}
// Max simple is the same as sum of positive winding number contributions of
// bounding box
@@ -326,10 +339,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 <<
@@ -374,16 +387,4 @@ inline typename DerivedV::Scalar
return igl::winding_number(BV,PBF,p);
}
// This is a bullshit template because AABB annoyingly needs templates for bad
// combinations of 3D V with DIM=2 AABB
//
// _Define_ as a no-op rather than monkeying around with the proper code above
namespace igl
{
template <> inline igl::WindingNumberAABB<Eigen::Matrix<double, 1, 3, 1, 1, 3>,Eigen::Matrix<double, -1, 2, 0, -1, 2>,Eigen::Matrix<int, -1, 2, 0, -1, 2>>::WindingNumberAABB(const Eigen::MatrixBase<Eigen::Matrix<double, -1, 2, 0, -1, 2>> & V, const Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2>> & F){};
template <> inline void igl::WindingNumberAABB<Eigen::Matrix<double, 1, 3, 1, 1, 3>,Eigen::Matrix<double, -1, 2, 0, -1, 2>,Eigen::Matrix<int, -1, 2, 0, -1, 2>>::grow(){};
template <> inline void igl::WindingNumberAABB<Eigen::Matrix<double, 1, 3, 1, 1, 3>,Eigen::Matrix<double, -1, 2, 0, -1, 2>,Eigen::Matrix<int, -1, 2, 0, -1, 2>>::init(){};
}
#endif
+4 -3
View File
@@ -9,14 +9,15 @@
#define IGL_WINDINGNUMBERMETHOD_H
namespace igl
{
// EXACT_WINDING_NUMBER_METHOD exact hierarchical evaluation
// APPROX_SIMPLE_WINDING_NUMBER_METHOD poor approximation
// APPROX_CACHE_WINDING_NUMBER_METHOD another poor approximation
enum WindingNumberMethod
{
// exact hierarchical evaluation
EXACT_WINDING_NUMBER_METHOD = 0,
// poor approximation
APPROX_SIMPLE_WINDING_NUMBER_METHOD = 1,
// another poor approximation
APPROX_CACHE_WINDING_NUMBER_METHOD = 2,
/// Number of winding number methods
NUM_WINDING_NUMBER_METHODS = 3
};
}
+108 -142
View File
@@ -11,74 +11,67 @@
#include <map>
#include <Eigen/Dense>
#include "WindingNumberMethod.h"
#include <memory>
namespace igl
{
// Space partitioning tree for computing winding number hierarchically.
//
// Templates:
// Point type for points in space, e.g. Eigen::Vector3d
/// Space partitioning tree for computing winding number hierarchically.
template <
typename Point,
typename DerivedV,
typename DerivedF >
typename Scalar,
typename Index>
class WindingNumberTree
{
public:
using Point = Eigen::Matrix<Scalar,1,3>;
// Method to use (see enum above)
//static double min_max_w;
static std::map<
std::pair<const WindingNumberTree*,const WindingNumberTree*>,
typename DerivedV::Scalar>
Scalar>
cached;
// This is only need to fill in references, it should never actually be touched
// and shouldn't cause race conditions. (This is a hack, but I think it's "safe")
static DerivedV dummyV;
protected:
WindingNumberMethod method;
const WindingNumberTree * parent;
std::list<WindingNumberTree * > children;
typedef
Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,Eigen::Dynamic>
Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>
MatrixXS;
typedef
Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,Eigen::Dynamic>
Eigen::Matrix<Index,Eigen::Dynamic,Eigen::Dynamic>
MatrixXF;
//// List of boundary edges (recall edges are vertices in 2d)
//const Eigen::MatrixXi boundary;
// Base mesh vertices
DerivedV & V;
// Base mesh vertices with duplicates removed
// Base mesh vertices with duplicates removed (root will fill this in and
// then everyone's Vptr will point to it.
MatrixXS SV;
// Shared pointer to base mesh vertices
std::shared_ptr<MatrixXS> Vptr;
// Facets in this bounding volume
MatrixXF F;
// Tessellated boundary curve
MatrixXF cap;
// Upper Bound on radius of enclosing ball
typename DerivedV::Scalar radius;
Scalar radius;
// (Approximate) center (of mass)
Point center;
public:
inline WindingNumberTree();
// For root
template <typename DerivedV, typename DerivedF>
inline WindingNumberTree(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F);
// For chilluns
inline WindingNumberTree(
const WindingNumberTree<Point,DerivedV,DerivedF> & parent,
const Eigen::MatrixBase<DerivedF> & F);
const WindingNumberTree<Scalar,Index> & parent,
const typename igl::WindingNumberTree<Scalar,Index>::MatrixXF & F);
inline virtual ~WindingNumberTree();
inline void delete_children();
inline virtual void set_mesh(
template <typename DerivedV, typename DerivedF>
inline void set_mesh(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F);
// Set method
inline void set_method( const WindingNumberMethod & m);
public:
inline const DerivedV & getV() const;
inline const MatrixXF & getF() const;
inline const MatrixXF & getcap() const;
// Grow the Tree recursively
inline virtual void grow();
// Determine whether a given point is inside the bounding
@@ -93,12 +86,12 @@ namespace igl
// Inputs:
// p query point
// Returns winding number
inline typename DerivedV::Scalar winding_number(const Point & p) const;
inline Scalar winding_number(const Point & p) const;
// Same as above, but always computes winding number using exact method
// (sum over every facet)
inline typename DerivedV::Scalar winding_number_all(const Point & p) const;
inline Scalar winding_number_all(const Point & p) const;
// Same as above, but always computes using sum over tessllated boundary
inline typename DerivedV::Scalar winding_number_boundary(const Point & p) const;
inline Scalar winding_number_boundary(const Point & p) const;
//// Same as winding_number above, but if max_simple_abs_winding_number is
//// less than some threshold min_max_w just return 0 (colloquially the "fast
//// multipole method)
@@ -121,10 +114,10 @@ namespace igl
// Inputs:
// p query point
// Returns max winding number of
inline virtual typename DerivedV::Scalar max_abs_winding_number(const Point & p) const;
inline virtual Scalar max_abs_winding_number(const Point & p) const;
// Same as above, but stronger assumptions on (V,F). Assumes (V,F) is a
// simple polyhedron
inline virtual typename DerivedV::Scalar max_simple_abs_winding_number(const Point & p) const;
inline virtual Scalar max_simple_abs_winding_number(const Point & p) const;
// Compute or read cached winding number for point p with respect to mesh
// in bounding box, recursing according to approximation criteria
//
@@ -132,7 +125,7 @@ namespace igl
// p query point
// that WindingNumberTree containing mesh w.r.t. which we're computing w.n.
// Returns cached winding number
inline virtual typename DerivedV::Scalar cached_winding_number(const WindingNumberTree & that, const Point & p) const;
inline virtual Scalar cached_winding_number(const WindingNumberTree & that, const Point & p) const;
};
}
@@ -143,89 +136,95 @@ 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(),
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(),
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)
{
using namespace std;
// 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 std::list<WindingNumberTree<Scalar,Index>* >::iterator cit = children.begin();
while(cit != children.end())
{
// clear the memory of this item
@@ -235,8 +234,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)
@@ -245,44 +244,23 @@ 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();
// If inside then we need to be careful
if(inside(p))
@@ -291,9 +269,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 std::list<WindingNumberTree<Scalar,Index>* >::const_iterator cit = children.begin();
cit != children.end();
cit++)
{
@@ -331,7 +309,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)
{
@@ -356,24 +334,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)
//{
@@ -388,46 +364,43 @@ 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<<"]";
std::cout<<tab<<"["<<std::endl<<F<<std::endl<<"]";
// Print children
for(
typename list<WindingNumberTree<Point,DerivedV,DerivedF>* >::iterator cit = children.begin();
typename std::list<WindingNumberTree<Scalar,Index>* >::iterator cit = children.begin();
cit != children.end();
cit++)
{
cout<<","<<endl;
(*cit)->print((string(tab)+"").c_str());
std::cout<<","<<std::endl;
(*cit)->print((std::string(tab)+"").c_str());
}
}
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 std::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;
// Simple metric for `is_far`
//
// this that
@@ -448,7 +421,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);
@@ -458,7 +431,7 @@ igl::WindingNumberTree<Point,DerivedV,DerivedF>::cached_winding_number(
if(is_far)
{
// Not implemented yet
pair<const WindingNumberTree*,const WindingNumberTree*> this_that(this,&that);
std::pair<const WindingNumberTree*,const WindingNumberTree*> this_that(this,&that);
// Need to compute it for first time?
if(cached.count(this_that)==0)
{
@@ -473,7 +446,7 @@ igl::WindingNumberTree<Point,DerivedV,DerivedF>::cached_winding_number(
}else
{
for(
typename list<WindingNumberTree<Point,DerivedV,DerivedF>* >::const_iterator cit = children.begin();
typename std::list<WindingNumberTree<Scalar,Index>* >::const_iterator cit = children.begin();
cit != children.end();
cit++)
{
@@ -491,11 +464,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
+10 -13
View File
@@ -11,14 +11,11 @@
#include <Eigen/Core>
namespace igl
{
// ACCUMARRY Like Matlab's accumarray. Accumulate values in V using subscripts
// in S.
//
// Inputs:
// S #S list of subscripts
// V #V list of values
// Outputs:
// A max(subs)+1 list of accumulated values
/// 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,
@@ -28,11 +25,11 @@ namespace igl
const Eigen::MatrixBase<DerivedS> & S,
const Eigen::MatrixBase<DerivedV> & V,
Eigen::PlainObjectBase<DerivedA> & A);
// Inputs:
// S #S list of subscripts
// V single value used for all
// Outputs:
// A max(subs)+1 list of accumulated values
/// 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
Executable → Regular
+55 -39
View File
@@ -11,6 +11,8 @@
#include "slice_into.h"
#include "cat.h"
//#include "matlab_format.h"
#include "placeholders.h"
#include "PlainMatrix.h"
#include <iostream>
#include <limits>
@@ -31,25 +33,24 @@ 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"
#endif
using namespace Eigen;
using namespace std;
SolverStatus ret = SOLVER_STATUS_ERROR;
const int n = A.rows();
assert(n == A.cols() && "A must be square");
@@ -72,7 +73,7 @@ IGL_INLINE igl::SolverStatus igl::active_set(
if(p_lx.size() == 0)
{
lx = Derivedlx::Constant(
n,1,-numeric_limits<typename Derivedlx::Scalar>::max());
n,1,-std::numeric_limits<typename Derivedlx::Scalar>::max());
}else
{
lx = p_lx;
@@ -80,7 +81,7 @@ IGL_INLINE igl::SolverStatus igl::active_set(
if(p_ux.size() == 0)
{
ux = Derivedux::Constant(
n,1,numeric_limits<typename Derivedux::Scalar>::max());
n,1,std::numeric_limits<typename Derivedux::Scalar>::max());
}else
{
ux = p_ux;
@@ -104,14 +105,12 @@ IGL_INLINE igl::SolverStatus igl::active_set(
typedef int BOOL;
#define TRUE 1
#define FALSE 0
Matrix<BOOL,Dynamic,1> as_lx = Matrix<BOOL,Dynamic,1>::Constant(n,1,FALSE);
Matrix<BOOL,Dynamic,1> as_ux = Matrix<BOOL,Dynamic,1>::Constant(n,1,FALSE);
Matrix<BOOL,Dynamic,1> as_ieq = Matrix<BOOL,Dynamic,1>::Constant(Aieq.rows(),1,FALSE);
Eigen::Matrix<BOOL,Eigen::Dynamic,1> as_lx = Eigen::Matrix<BOOL,Eigen::Dynamic,1>::Constant(n,1,FALSE);
Eigen::Matrix<BOOL,Eigen::Dynamic,1> as_ux = Eigen::Matrix<BOOL,Eigen::Dynamic,1>::Constant(n,1,FALSE);
Eigen::Matrix<BOOL,Eigen::Dynamic,1> as_ieq = Eigen::Matrix<BOOL,Eigen::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 +120,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 +165,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 +200,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;
@@ -225,7 +235,7 @@ IGL_INLINE igl::SolverStatus igl::active_set(
// PREPARE EQUALITY CONSTRAINTS
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;
{
@@ -243,7 +253,7 @@ IGL_INLINE igl::SolverStatus igl::active_set(
assert(k == as_ieq_count);
}
// extract active constraint rows
SparseMatrix<AeqT> Aeq_i,Aieq_i;
Eigen::SparseMatrix<AeqT> Aeq_i,Aieq_i;
slice(Aieq,as_ieq_list,1,Aieq_i);
// Append to equality constraints
cat(1,Aeq,Aieq_i,Aeq_i);
@@ -253,7 +263,7 @@ IGL_INLINE igl::SolverStatus igl::active_set(
#ifndef NDEBUG
{
// NO DUPES!
Matrix<BOOL,Dynamic,1> fixed = Matrix<BOOL,Dynamic,1>::Constant(n,1,FALSE);
Eigen::Matrix<BOOL ,Eigen::Dynamic,1> fixed = Eigen::Matrix<BOOL ,Eigen::Dynamic,1>::Constant(n,1,FALSE);
for(int k = 0;k<known_i.size();k++)
{
assert(!fixed[known_i(k)]);
@@ -262,7 +272,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 +280,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 +290,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 +308,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;
}
@@ -308,18 +324,18 @@ IGL_INLINE igl::SolverStatus igl::active_set(
}
// Compute Lagrange multiplier values for known_i
SparseMatrix<AT> Ak;
Eigen::SparseMatrix<AT> Ak;
// Slow
slice(A,known_i,1,Ak);
DerivedB Bk;
slice(B,known_i,Bk);
MatrixXd Lambda_known_i = -(0.5*Ak*Z + 0.5*Bk);
//slice(B,known_i,Bk);
PlainMatrix<DerivedB,Eigen::Dynamic> Bk = B(known_i,igl::placeholders::all);
Eigen::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) =
(-1*Lambda_known_i.block(nk,0,as_lx_count,1)).eval();
// Extract Lagrange multipliers for Aieq_i (always at back of sol)
VectorXd Lambda_Aieq_i(Aieq_i.rows(),1);
Eigen::VectorXd Lambda_Aieq_i(Aieq_i.rows(),1);
for(int l = 0;l<Aieq_i.rows();l++)
{
Lambda_Aieq_i(Aieq_i.rows()-1-l) = sol(sol.rows()-1-l);
@@ -365,6 +381,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
+58 -49
View File
@@ -16,39 +16,45 @@
namespace igl
{
struct active_set_params;
// Known Bugs: rows of [Aeq;Aieq] **must** be linearly independent. Should be
// using QR decomposition otherwise:
// https://v8doc.sas.com/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),
+1
View File
@@ -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;
+24 -18
View File
@@ -14,29 +14,35 @@
#include <vector>
namespace igl
{
// Constructs the graph adjacency list of a given mesh (V,F)
// Templates:
// T should be a eigen sparse matrix primitive type like int or double
// Inputs:
// F #F by dim list of mesh faces (must be triangles)
// sorted flag that indicates if the list should be sorted counter-clockwise
// Outputs:
// A vector<vector<T> > containing at row i the adjacent vertices of vertex i
//
// Example:
// // Mesh in (V,F)
// vector<vector<double> > A;
// adjacency_list(F,A);
//
// See also: edges, cotmatrix, diag
/// Constructs the graph adjacency list of a given mesh (V,F)
///
/// @tparam T should be a eigen sparse matrix primitive type like int or double
/// @param[in] F #F by dim list of mesh faces (must be triangles)
/// @param[out] A vector<vector<T> > containing at row i the adjacent vertices of vertex i
/// @param[in] sorted flag that indicates if the list should be sorted counter-clockwise. Input assumed to be manifold.
///
/// Example:
/// \code{.cpp}
/// // Mesh in (V,F)
/// vector<vector<double> > A;
/// adjacency_list(F,A);
/// \endcode
///
/// \see
/// adjacency_matrix
/// edges,
/// cotmatrix,
/// diag
template <typename Index, typename IndexVector>
IGL_INLINE void adjacency_list(
const Eigen::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,
+6 -9
View File
@@ -16,12 +16,10 @@ IGL_INLINE void igl::adjacency_matrix(
const Eigen::MatrixBase<DerivedF> & F,
Eigen::SparseMatrix<T>& A)
{
using namespace std;
using namespace Eigen;
typedef typename DerivedF::Scalar Index;
typedef Triplet<T> IJV;
vector<IJV > ijv;
typedef Eigen::Triplet<T> IJV;
std::vector<IJV > ijv;
ijv.reserve(F.size()*2);
// Loop over **simplex** (i.e., **not quad**)
for(int i = 0;i<F.rows();i++)
@@ -71,11 +69,8 @@ IGL_INLINE void igl::adjacency_matrix(
const Eigen::MatrixBase<DerivedC> & C,
Eigen::SparseMatrix<T>& A)
{
using namespace std;
using namespace Eigen;
typedef Triplet<T> IJV;
vector<IJV > ijv;
typedef Eigen::Triplet<T> IJV;
std::vector<IJV > ijv;
ijv.reserve(C(C.size()-1)*2);
typedef typename DerivedI::Scalar Index;
const Index n = I.maxCoeff()+1;
@@ -116,6 +111,8 @@ IGL_INLINE void igl::adjacency_matrix(
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, 3, 1, -1, 3>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3>> const&, Eigen::SparseMatrix<int, 0, int>&);
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>&);
+34 -33
View File
@@ -15,43 +15,44 @@
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)+1 by max(F)+1 adjacency 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
/// Eigen::SparseMatrix<double> Adiag;
/// diag(Asum,Adiag);
/// // Build uniform laplacian
/// Eigen::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.
//
// Inputs:
// I #I vectorized list of polygon corner indices into rows of some matrix V
// 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
// Outputs:
// A max(I)+1 by max(I)+1 adjacency matrix, each row i corresponding to V(i,:)
//
/// 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,
+9 -10
View File
@@ -12,16 +12,15 @@
#include <Eigen/Sparse>
namespace igl
{
// For Dense matrices use: A.rowwise().all() or A.colwise().all()
//
// Inputs:
// A m by n sparse matrix
// dim dimension along which to check for all (1 or 2)
// Output:
// B n-long vector (if dim == 1)
// or
// B m-long vector (if dim == 2)
//
/// Check whether all values are logically true along a dimension.
///
/// \note For Dense matrices use: A.rowwise().all() or A.colwise().all()
///
/// @param[in] A m by n sparse matrix
/// @param[in] dim dimension along which to check for all (1 or 2)
/// @param[out] B n-long vector (if dim == 1)
/// or m-long vector (if dim == 2)
///
template <typename AType, typename DerivedB>
IGL_INLINE void all(
const Eigen::SparseMatrix<AType> & A,
+10 -15
View File
@@ -11,21 +11,16 @@
namespace igl
{
// ALL_PAIRS_DISTANCES compute distances between each point i in V and point j
// in U
//
// D = all_pairs_distances(V,U)
//
// Templates:
// Mat matrix class like MatrixXd
// Inputs:
// V #V by dim list of points
// U #U by dim list of points
// squared whether to return squared distances
// Outputs:
// D #V by #U matrix of distances, where D(i,j) gives the distance or
// squareed distance between V(i,:) and U(j,:)
//
/// Compute distances between each point i in V and point j in U
///
/// D = all_pairs_distances(V,U)
///
/// @tparam matrix class like Eigen::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,
+30 -25
View File
@@ -22,29 +22,31 @@ 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::MatrixBase<DerivedP> & P,
const Eigen::MatrixBase<DerivedN> & N,
const int num_samples,
Eigen::PlainObjectBase<DerivedS> & S)
{
using namespace Eigen;
const int n = P.rows();
// 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 Eigen::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
@@ -76,17 +78,19 @@ IGL_INLINE void igl::ambient_occlusion(
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);
@@ -107,15 +111,17 @@ IGL_INLINE void igl::ambient_occlusion(
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,13 +133,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<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> >&);
// 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::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> >&);
// 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::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> >&);
// 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::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<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 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, -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
+34 -18
View File
@@ -13,17 +13,17 @@
#include <functional>
namespace igl
{
// Compute ambient occlusion per given point
//
// Inputs:
// shoot_ray function handle that outputs hits of a given ray against a
// mesh (embedded in function handles as captured variable/data)
// P #P by 3 list of origin points
// N #P by 3 list of origin normals
// Outputs:
// S #P list of ambient occlusion values between 1 (fully occluded) and
// 0 (not occluded)
//
/// Compute ambient occlusion per given point using ray-mesh intersection
/// function handle.
///
/// @param[in] shoot_ray function handle that outputs hits of a given ray against a
/// mesh (embedded in function handles as captured variable/data)
/// @param[in] P #P by 3 list of origin points
/// @param[in] N #P by 3 list of origin normals
/// @param[in] num_samples number of samples to use (e.g., 1000)
/// @param[out] S #P list of ambient occlusion values between 1 (fully occluded) and
/// 0 (not occluded)
///
template <
typename DerivedP,
typename DerivedN,
@@ -31,15 +31,25 @@ namespace igl
IGL_INLINE void ambient_occlusion(
const std::function<
bool(
const Eigen::Vector3f&,
const Eigen::Vector3f&)
const Eigen::Matrix<typename DerivedP::Scalar,3,1>&,
const Eigen::Matrix<typename DerivedP::Scalar,3,1>&)
> & shoot_ray,
const Eigen::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,
@@ -55,9 +65,15 @@ namespace igl
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,
+2 -2
View File
@@ -6,8 +6,8 @@
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "angular_distance.h"
#include <igl/EPS.h>
#include <igl/PI.h>
#include "EPS.h"
#include "PI.h"
IGL_INLINE double igl::angular_distance(
const Eigen::Quaterniond & A,
const Eigen::Quaterniond & B)
+6 -7
View File
@@ -11,13 +11,12 @@
#include <Eigen/Geometry>
namespace igl
{
// The "angular distance" between two unit quaternions is the angle of the
// smallest rotation (treated as an Axis and Angle) that takes A to B.
//
// Inputs:
// A unit quaternion
// B unit quaternion
// Returns angular distance
/// The "angular distance" between two unit quaternions is the angle of the
/// smallest rotation (treated as an Axis and Angle) that takes A to B.
///
/// @param[in] A unit quaternion
/// @param[in] B unit quaternion
/// @return angular distance
IGL_INLINE double angular_distance(
const Eigen::Quaterniond & A,
const Eigen::Quaterniond & B);
+9 -10
View File
@@ -12,16 +12,15 @@
#include <Eigen/Sparse>
namespace igl
{
// For Dense matrices use: A.rowwise().any() or A.colwise().any()
//
// Inputs:
// A m by n sparse matrix
// dim dimension along which to check for any (1 or 2)
// Output:
// B n-long vector (if dim == 1)
// or
// B m-long vector (if dim == 2)
//
/// Check whether any values are logically true along a dimension.
///
/// \note Dense matrices use: A.rowwise().any() or A.colwise().any()
///
/// @param[in] A m by n sparse matrix
/// @param[in] dim dimension along which to check for any (1 or 2)
/// @param[out] B n-long vector (if dim == 1)
/// or m-long vector (if dim == 2)
///
template <typename AType, typename DerivedB>
IGL_INLINE void any(
const Eigen::SparseMatrix<AType> & A,
-20
View File
@@ -1,20 +0,0 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "any_of.h"
#include <Eigen/Core>
template <typename Mat>
IGL_INLINE bool igl::any_of(const Mat & S)
{
return std::any_of(S.data(),S.data()+S.size(),[](bool s){return s;});
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template bool igl::any_of<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::Matrix<int, -1, 1, 0, -1, 1> const&);
#endif
-26
View File
@@ -1,26 +0,0 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ANY_OF_H
#define IGL_ANY_OF_H
#include "igl_inline.h"
namespace igl
{
// Wrapper for STL `any_of` for matrix types
//
// Inputs:
// S matrix
// Returns whether any entries are true
//
// Seems that Eigen (now) implements this for `Eigen::Array`
template <typename Mat>
IGL_INLINE bool any_of(const Mat & S);
}
#ifndef IGL_STATIC_LIBRARY
# include "any_of.cpp"
#endif
#endif
+22 -29
View File
@@ -14,7 +14,6 @@
#include "speye.h"
#include "mode.h"
#include "project_isometrically_to_plane.h"
#include "slice.h"
#include "arap_rhs.h"
#include "repdiag.h"
#include "columnize.h"
@@ -36,8 +35,6 @@ IGL_INLINE bool igl::arap_precomputation(
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
@@ -54,14 +51,14 @@ IGL_INLINE bool igl::arap_precomputation(
data.dim = dim;
//assert(dim == 3 && "Only 3d supported");
// Defaults
data.f_ext = MatrixXd::Zero(n,data.dim);
data.f_ext = Eigen::MatrixXd::Zero(n,data.dim);
assert(data.dim <= V.cols() && "solve dim should be <= embedding");
bool flat = (V.cols() - data.dim)==1;
MatrixXX<Scalar> plane_V;
MatrixXX<Integer> plane_F;
typedef SparseMatrix<Scalar> SparseMatrixS;
typedef Eigen::SparseMatrix<Scalar> SparseMatrixS;
SparseMatrixS ref_map,ref_map_dim;
if(flat)
{
@@ -107,7 +104,7 @@ IGL_INLINE bool igl::arap_precomputation(
// Get group sum scatter matrix, when applied sums all entries of the same
// group according to G
SparseMatrix<double> G_sum;
Eigen::SparseMatrix<double> G_sum;
if(data.G.size() == 0)
{
if(eff_energy == ARAP_ENERGY_TYPE_ELEMENTS)
@@ -123,12 +120,10 @@ IGL_INLINE bool igl::arap_precomputation(
if(eff_energy == ARAP_ENERGY_TYPE_ELEMENTS)
{
Eigen::Matrix<int,Eigen::Dynamic,1> GG;
MatrixXi GF(F.rows(),F.cols());
Eigen::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;
@@ -136,7 +131,7 @@ IGL_INLINE bool igl::arap_precomputation(
//printf("group_sum_matrix()\n");
group_sum_matrix(data.G,G_sum);
}
SparseMatrix<double> G_sum_dim;
Eigen::SparseMatrix<double> G_sum_dim;
repdiag(G_sum,data.dim,G_sum_dim);
assert(G_sum_dim.cols() == data.CSM.rows());
data.CSM = (G_sum_dim * data.CSM).eval();
@@ -149,24 +144,24 @@ IGL_INLINE bool igl::arap_precomputation(
}
assert(data.K.rows() == data.n*data.dim);
SparseMatrix<double> Q = (-L).eval();
Eigen::SparseMatrix<double> Q = (-L).eval();
if(data.with_dynamics)
{
const double h = data.h;
assert(h != 0);
SparseMatrix<double> M;
Eigen::SparseMatrix<double> M;
massmatrix(V,F,MASSMATRIX_TYPE_DEFAULT,data.M);
const double dw = (1./data.ym)*(h*h);
SparseMatrix<double> DQ = dw * 1./(h*h)*data.M;
Eigen::SparseMatrix<double> DQ = dw * 1./(h*h)*data.M;
Q += DQ;
// Dummy external forces
data.f_ext = MatrixXd::Zero(n,data.dim);
data.vel = MatrixXd::Zero(n,data.dim);
data.f_ext = Eigen::MatrixXd::Zero(n,data.dim);
data.vel = Eigen::MatrixXd::Zero(n,data.dim);
}
return min_quad_with_fixed_precompute(
Q,b,SparseMatrix<double>(),true,data.solver_data);
Q,b,Eigen::SparseMatrix<double>(),true,data.solver_data);
}
template <
@@ -177,8 +172,6 @@ IGL_INLINE bool igl::arap_solve(
ARAPData & data,
Eigen::MatrixBase<DerivedU> & U)
{
using namespace Eigen;
using namespace std;
assert(data.b.size() == bc.rows());
assert(U.size() != 0 && "U cannot be empty");
assert(U.cols() == data.dim && "U.cols() match data.dim");
@@ -188,9 +181,9 @@ IGL_INLINE bool igl::arap_solve(
const int n = data.n;
int iter = 0;
// changes each arap iteration
MatrixXd U_prev = U;
Eigen::MatrixXd U_prev = U;
// doesn't change for fixed with_dynamics timestep
MatrixXd U0;
Eigen::MatrixXd U0;
if(data.with_dynamics)
{
U0 = U_prev;
@@ -207,13 +200,13 @@ IGL_INLINE bool igl::arap_solve(
const auto & Udim = U.replicate(data.dim,1);
assert(U.cols() == data.dim);
// As if U.col(2) was 0
MatrixXd S = data.CSM * Udim;
Eigen::MatrixXd S = data.CSM * Udim;
// THIS NORMALIZATION IS IMPORTANT TO GET SINGLE PRECISION SVD CODE TO WORK
// CORRECTLY.
S /= S.array().abs().maxCoeff();
const int Rdim = data.dim;
MatrixXd R(Rdim,data.CSM.rows());
Eigen::MatrixXd R(Rdim,data.CSM.rows());
if(R.rows() == 2)
{
fit_rotations_planar(S,R);
@@ -228,14 +221,14 @@ IGL_INLINE bool igl::arap_solve(
}
//for(int k = 0;k<(data.CSM.rows()/dim);k++)
//{
// R.block(0,dim*k,dim,dim) = MatrixXd::Identity(dim,dim);
// R.block(0,dim*k,dim,dim) = Eigen::MatrixXd::Identity(dim,dim);
//}
// Number of rotations: #vertices or #elements
int num_rots = data.K.cols()/Rdim/Rdim;
// distribute group rotations to vertices in each group
MatrixXd eff_R;
Eigen::MatrixXd eff_R;
if(data.G.size() == 0)
{
// copy...
@@ -250,7 +243,7 @@ IGL_INLINE bool igl::arap_solve(
}
}
MatrixXd Dl;
Eigen::MatrixXd Dl;
if(data.with_dynamics)
{
assert(data.M.rows() == n &&
@@ -266,13 +259,13 @@ IGL_INLINE bool igl::arap_solve(
Dl = dw * (1./(h*h)*data.M*(-U0 - h*data.vel) - data.f_ext);
}
VectorXd Rcol;
Eigen::VectorXd Rcol;
columnize(eff_R,num_rots,2,Rcol);
VectorXd Bcol = -data.K * Rcol;
Eigen::VectorXd Bcol = -data.K * Rcol;
assert(Bcol.size() == data.n*data.dim);
for(int c = 0;c<data.dim;c++)
{
VectorXd Uc,Bc,bcc,Beq;
Eigen::VectorXd Uc,Bc,bcc,Beq;
Bc = Bcol.block(c*n,0,n,1);
if(data.with_dynamics)
{
+51 -40
View File
@@ -15,36 +15,41 @@
namespace igl
{
/// Parameters and precomputed values for arap solver.
///
/// \fileinfo
struct ARAPData
{
// n #V
// G #V list of group indices (1 to k) for each vertex, such that vertex i
// is assigned to group G(i)
// energy type of energy to use
// with_dynamics whether using dynamics (need to call arap_precomputation
// after changing)
// f_ext #V by dim list of external forces
// vel #V by dim list of velocities
// h dynamics time step
// ym ~Young's modulus smaller is softer, larger is more rigid/stiff
// max_iter maximum inner iterations
// K rhs pre-multiplier
// M mass matrix
// solver_data quadratic solver data
// b list of boundary indices into V
// dim dimension being used for solving
/// #V size of mesh
int n;
/// #V list of group indices (1 to k) for each vertex, such that vertex i
/// is assigned to group G(i)
Eigen::VectorXi G;
/// type of energy to use
ARAPEnergyType energy;
/// whether using dynamics (need to call arap_precomputation after changing)
bool with_dynamics;
Eigen::MatrixXd f_ext,vel;
/// #V by dim list of external forces
Eigen::MatrixXd f_ext;
/// #V by dim list of velocities
Eigen::MatrixXd vel;
/// dynamics time step
double h;
/// "Young's modulus" smaller is softer, larger is more rigid/stiff
double ym;
/// maximum inner iterations
int max_iter;
Eigen::SparseMatrix<double> K,M;
/// @private rhs pre-multiplier
Eigen::SparseMatrix<double> K;
/// @private mass matrix
Eigen::SparseMatrix<double> M;
/// @private covariance scatter matrix
Eigen::SparseMatrix<double> CSM;
/// @private quadratic solver data
min_quad_with_fixed_data<double> solver_data;
/// @private list of boundary indices into V
Eigen::VectorXi b;
/// @private dimension being used for solving
int dim;
ARAPData():
n(0),
@@ -64,16 +69,19 @@ 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,
@@ -84,18 +92,21 @@ namespace igl
const int dim,
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
//
// 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.
/// 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>
+80 -51
View File
@@ -6,6 +6,7 @@
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "arap_dof.h"
#include "IGL_ASSERT.h"
#include "cotmatrix.h"
#include "massmatrix.h"
@@ -25,15 +26,36 @@
#include "verbose.h"
#include "print_ijv.h"
#include "get_seconds_hires.h"
//#include "MKLEigenInterface.h"
#include "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>
@@ -44,8 +66,7 @@ IGL_INLINE bool igl::arap_dof_precomputation(
const Eigen::Matrix<int,Eigen::Dynamic,1> & G,
ArapDOFData<LbsMatrixType, SSCALAR> & data)
{
using namespace Eigen;
typedef Matrix<SSCALAR, Dynamic, Dynamic> MatrixXS;
typedef Eigen::Matrix<SSCALAR, Eigen::Dynamic, Eigen::Dynamic> MatrixXS;
// number of mesh (domain) vertices
int n = V.rows();
// cache problem size
@@ -73,11 +94,11 @@ IGL_INLINE bool igl::arap_dof_precomputation(
//printf("n=%d; dim=%d; m=%d;\n",n,data.dim,data.m);
// Build cotangent laplacian
SparseMatrix<double> Lcot;
Eigen::SparseMatrix<double> Lcot;
//printf("cotmatrix()\n");
cotmatrix(V,F,Lcot);
// Discrete laplacian (should be minus matlab version)
SparseMatrix<double> Lapl = -2.0*Lcot;
Eigen::SparseMatrix<double> Lapl = -2.0*Lcot;
#ifdef EXTREME_VERBOSE
cout<<"LaplIJV=["<<endl;print_ijv(Lapl,1);cout<<endl<<"];"<<
endl<<"Lapl=sparse(LaplIJV(:,1),LaplIJV(:,2),LaplIJV(:,3),"<<
@@ -86,7 +107,7 @@ IGL_INLINE bool igl::arap_dof_precomputation(
// Get group sum scatter matrix, when applied sums all entries of the same
// group according to G
SparseMatrix<double> G_sum;
Eigen::SparseMatrix<double> G_sum;
if(G.size() == 0)
{
speye(n,G_sum);
@@ -96,12 +117,10 @@ IGL_INLINE bool igl::arap_dof_precomputation(
Eigen::Matrix<int,Eigen::Dynamic,1> GG;
if(data.energy == ARAP_ENERGY_TYPE_ELEMENTS)
{
MatrixXi GF(F.rows(),F.cols());
Eigen::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
@@ -120,7 +139,7 @@ IGL_INLINE bool igl::arap_dof_precomputation(
// Get covariance scatter matrix, when applied collects the covariance matrices
// used to fit rotations to during optimization
SparseMatrix<double> CSM;
Eigen::SparseMatrix<double> CSM;
//printf("covariance_scatter_matrix()\n");
covariance_scatter_matrix(V,F,data.energy,CSM);
#ifdef EXTREME_VERBOSE
@@ -147,7 +166,7 @@ IGL_INLINE bool igl::arap_dof_precomputation(
// S((k-1)*dim + 1:dim,:)
// Apply group sum to each dimension's block of covariance scatter matrix
SparseMatrix<double> G_sum_dim;
Eigen::SparseMatrix<double> G_sum_dim;
repdiag(G_sum,data.dim,G_sum_dim);
CSM = (G_sum_dim * CSM).eval();
#ifdef EXTREME_VERBOSE
@@ -183,13 +202,26 @@ 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<Eigen::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<Eigen::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());
for(int j = 0;j<data.dim;j++)
{
SparseMatrix<double> CSMj;
Eigen::SparseMatrix<double> CSMj;
//printf("CSM_M(): slice\n");
slice(
CSM,
@@ -203,7 +235,7 @@ IGL_INLINE bool igl::arap_dof_precomputation(
{
// Convert to full
//printf("CSM_M(): full\n");
MatrixXd CSMjM_ifull(CSMjM_i);
Eigen::MatrixXd CSMjM_ifull(CSMjM_i);
// printf("CSM_M[%d]: %d %d\n",i,data.CSM_M[i].rows(),data.CSM_M[i].cols());
// printf("CSM_M[%d].block(%d*%d=%d,0,%d,%d): %d %d\n",i,j,k,CSMjM_i.rows(),CSMjM_i.cols(),
// data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()).rows(),
@@ -223,7 +255,7 @@ IGL_INLINE bool igl::arap_dof_precomputation(
// precompute arap_rhs matrix
//printf("arap_rhs()\n");
SparseMatrix<double> K;
Eigen::SparseMatrix<double> K;
arap_rhs(V,F,V.cols(),data.energy,K);
//#ifdef EXTREME_VERBOSE
// cout<<"KIJV=["<<endl;print_ijv(K,1);cout<<endl<<"];"<<
@@ -231,8 +263,8 @@ IGL_INLINE bool igl::arap_dof_precomputation(
// K.rows()<<","<<K.cols()<<");"<<endl;
//#endif
// Precompute left muliplication by M and right multiplication by G_sum
SparseMatrix<double> G_sumT = G_sum.transpose();
SparseMatrix<double> G_sumT_dim_dim;
Eigen::SparseMatrix<double> G_sumT = G_sum.transpose();
Eigen::SparseMatrix<double> G_sumT_dim_dim;
repdiag(G_sumT,data.dim*data.dim,G_sumT_dim_dim);
LbsMatrixType MT = M.transpose();
// If this is a bottle neck then consider reordering matrix multiplication
@@ -245,7 +277,7 @@ IGL_INLINE bool igl::arap_dof_precomputation(
// Precompute system matrix
//printf("A()\n");
SparseMatrix<double> A;
Eigen::SparseMatrix<double> A;
repdiag(Lapl,data.dim,A);
data.Q = MT * (A * M);
//#ifdef EXTREME_VERBOSE
@@ -258,19 +290,19 @@ IGL_INLINE bool igl::arap_dof_precomputation(
//if(data.with_dynamics)
//{
// Build cotangent laplacian
SparseMatrix<double> Mass;
Eigen::SparseMatrix<double> Mass;
//printf("massmatrix()\n");
massmatrix(V,F,(F.cols()>3?MASSMATRIX_TYPE_BARYCENTRIC:MASSMATRIX_TYPE_VORONOI),Mass);
//cout<<"MIJV=["<<endl;print_ijv(Mass,1);cout<<endl<<"];"<<
// endl<<"M=sparse(MIJV(:,1),MIJV(:,2),MIJV(:,3),"<<
// Mass.rows()<<","<<Mass.cols()<<");"<<endl;
//speye(data.n,Mass);
SparseMatrix<double> Mass_rep;
Eigen::SparseMatrix<double> Mass_rep;
repdiag(Mass,data.dim,Mass_rep);
// Multiply either side by weights matrix (should be dense)
data.Mass_tilde = MT * Mass_rep * M;
MatrixXd ones(data.dim*data.n,data.dim);
Eigen::MatrixXd ones(data.dim*data.n,data.dim);
for(int i = 0;i<data.n;i++)
{
for(int d = 0;d<data.dim;d++)
@@ -498,8 +530,7 @@ IGL_INLINE bool igl::arap_dof_recomputation(
const Eigen::SparseMatrix<double> & A_eq,
ArapDOFData<LbsMatrixType, SSCALAR> & data)
{
using namespace Eigen;
typedef Matrix<SSCALAR, Dynamic, Dynamic> MatrixXS;
typedef Eigen::Matrix<SSCALAR, Eigen::Dynamic, Eigen::Dynamic> MatrixXS;
LbsMatrixType * Q;
LbsMatrixType Qdyn;
@@ -544,16 +575,16 @@ IGL_INLINE bool igl::arap_dof_recomputation(
// Compute dense solve matrix (alternative of matrix factorization)
//printf("kkt_inverse()\n");
MatrixXd Qfull(*Q);
MatrixXd A_eqfull(A_eq);
MatrixXd M_Solve;
Eigen::MatrixXd Qfull(*Q);
Eigen::MatrixXd A_eqfull(A_eq);
Eigen::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"));
kkt_inverse(Qfull, A_eqfull, use_lu,M_Solve);
double timer0_end = get_seconds_hires();
double timer0_end = get_seconds();
verbose("Bob timing: %.20f\n", (timer0_end - timer0_start)*1000.0);
// Precompute full solve matrix:
@@ -613,17 +644,16 @@ IGL_INLINE bool igl::arap_dof_update(
Eigen::MatrixXd & L
)
{
using namespace Eigen;
typedef Matrix<SSCALAR, Dynamic, Dynamic> MatrixXS;
typedef Eigen::Matrix<SSCALAR, Eigen::Dynamic, Eigen::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
@@ -667,10 +697,9 @@ IGL_INLINE bool igl::arap_dof_update(
MatrixXS S(k*data.dim,data.dim);
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);
Eigen::Matrix<SSCALAR ,Eigen::Dynamic,1> B_eq_SSCALAR = B_eq.cast<SSCALAR>();
Eigen::Matrix<SSCALAR ,Eigen::Dynamic,1> L0SSCALAR = L0.cast<SSCALAR>();
Eigen::Matrix<SSCALAR ,Eigen::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 +715,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 +726,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 +751,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 +776,7 @@ IGL_INLINE bool igl::arap_dof_update(
if(data.print_timings)
{
sec_fitRotations = get_seconds_hires();
sec_fitRotations = get_seconds();
}
///////////////////////////////////////////////////////////////////////////
@@ -766,7 +795,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;
@@ -799,13 +828,13 @@ IGL_INLINE bool igl::arap_dof_update(
( (-1.0/(data.h*data.h)) * data.L0.array() +
(1.0/(data.h)) * data.Lvel0.array()
).matrix();
MatrixXd temp_d = temp.template cast<double>();
Eigen::MatrixXd temp_d = temp.template cast<double>();
MatrixXd temp_g = data.fgrav*(data.grav_mag*data.grav_dir);
Eigen::MatrixXd temp_g = data.fgrav*(data.grav_mag*data.grav_dir);
assert(data.fext.rows() == temp_g.rows());
assert(data.fext.cols() == temp_g.cols());
MatrixXd temp2 = data.Mass_tilde * temp_d + temp_g + data.fext.template cast<double>();
Eigen::MatrixXd temp2 = data.Mass_tilde * temp_d + temp_g + data.fext.template cast<double>();
MatrixXS temp2_f = temp2.template cast<SSCALAR>();
L_part1_dyn = data.Pi_1 * temp2_f;
L_part1.array() = L_part1.array() + L_part1_dyn.array();
@@ -824,7 +853,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 +864,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 +890,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",
+136 -134
View File
@@ -14,75 +14,76 @@
#include "ARAPEnergyType.h"
#include <vector>
/// @file arap_dof.h
/// @brief "Fast Automatic Skinning Transformations" [Jacobson et al.\ 2012]
///
/// Arap DOF precomputation consists of two parts the computation. The first is
/// that which depends solely on the mesh (V,F), the linear blend skinning
/// weights (M) and the groups G. Then there's the part that depends on the
/// previous precomputation and the list of free and fixed vertices.
///
///
/// #### Caller example:
///
/// Once:
/// arap_dof_precomputation(...)
///
/// Each frame:
/// while(not satisfied)
/// arap_dof_update(...)
/// end
/// The code and variables differ from the description in Section 3 of "Fast
/// Automatic Skinning Transformations" by [Jacobson et al. 2012]
///
/// Here is a useful conversion table:
///
/// [article] [code]
/// S = \tilde{K} T S = CSM * Lsep
/// S --> R S --> R --shuffled--> Rxyz
/// Gamma_solve RT = Pi_1 \tilde{K} RT L_part1xyz = CSolveBlock1 * Rxyz
/// Pi_1 \tilde{K} CSolveBlock1
/// Peq = [T_full; P_pos]
/// T_full B_eq_fix <--- L0
/// P_pos B_eq
/// Pi_2 * P_eq = Lpart2and3 = Lpart2 + Lpart3
/// Pi_2_left T_full + Lpart3 = M_fullsolve(right) * B_eq_fix
/// Pi_2_right P_pos Lpart2 = M_fullsolve(left) * B_eq
/// T = [Pi_1 Pi_2] [\tilde{K}TRT P_eq] L = Lpart1 + Lpart2and3
///
namespace igl
{
// Caller example:
//
// Once:
// arap_dof_precomputation(...)
//
// Each frame:
// while(not satisfied)
// arap_dof_update(...)
// end
template <typename LbsMatrixType, typename SSCALAR>
struct ArapDOFData;
///////////////////////////////////////////////////////////////////////////
//
// Arap DOF precomputation consists of two parts the computation. The first is
// that which depends solely on the mesh (V,F), the linear blend skinning
// weights (M) and the groups G. Then there's the part that depends on the
// previous precomputation and the list of free and fixed vertices.
//
///////////////////////////////////////////////////////////////////////////
// The code and variables differ from the description in Section 3 of "Fast
// Automatic Skinning Transformations" by [Jacobson et al. 2012]
//
// Here is a useful conversion table:
//
// [article] [code]
// S = \tilde{K} T S = CSM * Lsep
// S --> R S --> R --shuffled--> Rxyz
// Gamma_solve RT = Pi_1 \tilde{K} RT L_part1xyz = CSolveBlock1 * Rxyz
// Pi_1 \tilde{K} CSolveBlock1
// Peq = [T_full; P_pos]
// T_full B_eq_fix <--- L0
// P_pos B_eq
// Pi_2 * P_eq = Lpart2and3 = Lpart2 + Lpart3
// Pi_2_left T_full + Lpart3 = M_fullsolve(right) * B_eq_fix
// Pi_2_right P_pos Lpart2 = M_fullsolve(left) * B_eq
// T = [Pi_1 Pi_2] [\tilde{K}TRT P_eq] L = Lpart1 + Lpart2and3
//
// Precomputes the system we are going to optimize. This consists of building
// constructor matrices (to compute covariance matrices from transformations
// and to build the poisson solve right hand side from rotation matrix entries)
// and also prefactoring the poisson system.
//
// Inputs:
// V #V by dim list of vertex positions
// F #F by {3|4} list of face indices
// M #V * dim by #handles * dim * (dim+1) matrix such that
// new_V(:) = LBS(V,W,A) = reshape(M * A,size(V)), where A is a column
// vectors formed by the entries in each handle's dim by dim+1
// transformation matrix. Specifcally, A =
// reshape(permute(Astack,[3 1 2]),n*dim*(dim+1),1)
// or A = [Lxx;Lyx;Lxy;Lyy;tx;ty], and likewise for other dim
// if Astack(:,:,i) is the dim by (dim+1) transformation at handle i
// handles are ordered according to P then BE (point handles before bone
// handles)
// G #V list of group indices (1 to k) for each vertex, such that vertex i
// is assigned to group G(i)
// Outputs:
// data structure containing all necessary precomputation for calling
// arap_dof_update
// Returns true on success, false on error
//
// See also: lbs_matrix_column
/// Precomputes the system to optimize for "Fast Automatic Skinning
/// Transformations" [Jacobson et al.\ 2012] skinning degrees of freedom
/// optimization using as-rigid-as-possible energy. This consists of building
/// constructor matrices (to compute covariance matrices from transformations
/// and to build the poisson solve right hand side from rotation matrix entries)
/// and also prefactoring the poisson system.
///
/// @param[in] V #V by dim list of vertex positions
/// @param[in] F #F by {3|4} list of face indices
/// @param[in] M #V * dim by #handles * dim * (dim+1) matrix such that
/// new_V(:) = LBS(V,W,A) = reshape(M * A,size(V)), where A is a column
/// vectors formed by the entries in each handle's dim by dim+1
/// transformation matrix. Specifcally, A =
/// reshape(permute(Astack,[3 1 2]),n*dim*(dim+1),1)
/// or A = [Lxx;Lyx;Lxy;Lyy;tx;ty], and likewise for other dim
/// if Astack(:,:,i) is the dim by (dim+1) transformation at handle i
/// handles are ordered according to P then BE (point handles before bone
/// handles)
/// @param[in] G #V list of group indices (1 to k) for each vertex, such that vertex i
/// is assigned to group G(i)
/// @param[out] data structure containing all necessary precomputation for calling
/// arap_dof_update
/// @return true on success, false on error
///
/// \see lbs_matrix_column
///
/// \fileinfo
template <typename LbsMatrixType, typename SSCALAR>
IGL_INLINE bool arap_dof_precomputation(
const Eigen::MatrixXd & V,
@@ -91,49 +92,49 @@ namespace igl
const Eigen::Matrix<int,Eigen::Dynamic,1> & G,
ArapDOFData<LbsMatrixType, SSCALAR> & data);
// Should always be called after arap_dof_precomputation, but may be called in
// between successive calls to arap_dof_update, recomputes precomputation
// given that there are only changes in free and fixed
//
// Inputs:
// fixed_dim list of transformation element indices for fixed (or partailly
// fixed) handles: not necessarily the complement of 'free'
// NOTE: the constraints for fixed transformations still need to be
// present in A_eq
// A_eq dim*#constraint_points by m*dim*(dim+1) matrix of linear equality
// constraint coefficients. Each row corresponds to a linear constraint,
// so that A_eq * L = Beq says that the linear transformation entries in
// the column L should produce the user supplied positional constraints
// for each handle in Beq. The row A_eq(i*dim+d) corresponds to the
// constrain on coordinate d of position i
// Outputs:
// data structure containing all necessary precomputation for calling
// arap_dof_update
// Returns true on success, false on error
//
// See also: lbs_matrix_column
/// Should always be called after arap_dof_precomputation, but may be called in
/// between successive calls to arap_dof_update, recomputes precomputation
/// given that there are only changes in free and fixed
///
/// @param[in] fixed_dim list of transformation element indices for fixed (or partailly
/// fixed) handles: not necessarily the complement of 'free'
/// NOTE: the constraints for fixed transformations still need to be
/// present in A_eq
/// @param[in] A_eq dim*#constraint_points by m*dim*(dim+1) matrix of linear equality
/// constraint coefficients. Each row corresponds to a linear constraint,
/// so that A_eq * L = Beq says that the linear transformation entries in
/// the column L should produce the user supplied positional constraints
/// for each handle in Beq. The row A_eq(i*dim+d) corresponds to the
/// constrain on coordinate d of position i
/// @param[out] data structure containing all necessary precomputation for calling
/// arap_dof_update
/// @return true on success, false on error
///
/// \see lbs_matrix_column
///
/// \fileinfo
template <typename LbsMatrixType, typename SSCALAR>
IGL_INLINE bool arap_dof_recomputation(
const Eigen::Matrix<int,Eigen::Dynamic,1> & fixed_dim,
const Eigen::SparseMatrix<double> & A_eq,
ArapDOFData<LbsMatrixType, SSCALAR> & data);
// Optimizes the transformations attached to each weight function based on
// precomputed system.
//
// Inputs:
// data precomputation data struct output from arap_dof_precomputation
// Beq dim*#constraint_points constraint values.
// L0 #handles * dim * dim+1 list of initial guess transformation entries,
// also holds fixed transformation entries for fixed handles
// max_iters maximum number of iterations
// tol stopping criteria parameter. If variables (linear transformation
// matrix entries) change by less than 'tol' the optimization terminates,
// 0.75 (weak tolerance)
// 0.0 (extreme tolerance)
// Outputs:
// L #handles * dim * dim+1 list of final optimized transformation entries,
// allowed to be the same as L
/// Optimizes the transformations attached to each weight function based on
/// precomputed system.
///
/// @param[in] data precomputation data struct output from arap_dof_precomputation
/// @param[in] Beq dim*#constraint_points constraint values.
/// @param[in] L0 #handles * dim * dim+1 list of initial guess transformation entries,
/// also holds fixed transformation entries for fixed handles
/// @param[in] max_iters maximum number of iterations
/// @param[in] tol stopping criteria parameter. If variables (linear transformation
/// matrix entries) change by less than 'tol' the optimization terminates,
/// 0.75 (weak tolerance)
/// 0.0 (extreme tolerance)
/// @param[out] L #handles * dim * dim+1 list of final optimized transformation entries,
/// allowed to be the same as L
///
/// \fileinfo
template <typename LbsMatrixType, typename SSCALAR>
IGL_INLINE bool arap_dof_update(
const ArapDOFData<LbsMatrixType,SSCALAR> & data,
@@ -144,88 +145,89 @@ namespace igl
Eigen::MatrixXd & L
);
// Structure that contains fields for all precomputed data or data that needs
// to be remembered at update
/// Structure that contains fields for all precomputed data or data that needs
/// to be remembered at update
///
/// \fileinfo
template <typename LbsMatrixType, typename SSCALAR>
struct ArapDOFData
{
/// Matrix with SSCALAR type
typedef Eigen::Matrix<SSCALAR, Eigen::Dynamic, Eigen::Dynamic> MatrixXS;
// Type of arap energy we're solving
/// Type of arap energy we're solving
igl::ARAPEnergyType energy;
//// LU decomposition precomptation data; note: not used by araf_dop_update
//// any more, replaced by M_FullSolve
//igl::min_quad_with_fixed_data<double> lu_data;
// List of indices of fixed transformation entries
/// List of indices of fixed transformation entries
Eigen::Matrix<int,Eigen::Dynamic,1> fixed_dim;
// List of precomputed covariance scatter matrices multiplied by lbs
// matrices
//std::vector<Eigen::SparseMatrix<double> > CSM_M;
/// List of precomputed covariance scatter matrices multiplied by lbs
/// matrices
std::vector<Eigen::MatrixXd> CSM_M;
/// @private
LbsMatrixType M_KG;
// Number of mesh vertices
/// Number of mesh vertices
int n;
// Number of weight functions
/// Number of weight functions
int m;
// Number of dimensions
/// Number of dimensions
int dim;
// Effective dimensions
/// Effective dimensions
int effective_dim;
// List of indices into C of positional constraints
/// List of indices into C of positional constraints
Eigen::Matrix<int,Eigen::Dynamic,1> interpolated;
/// Mask of free variables
std::vector<bool> free_mask;
// Full quadratic coefficients matrix before lagrangian (should be dense)
/// Full quadratic coefficients matrix before lagrangian (should be dense)
LbsMatrixType Q;
//// Solve matrix for the global step
//Eigen::MatrixXd M_Solve; // TODO: remove from here
// Full solve matrix that contains also conversion from rotations to the right hand side,
// i.e., solves Poisson transformations just from rotations and positional constraints
/// Full solve matrix that contains also conversion from rotations to the right hand side,
/// i.e., solves Poisson transformations just from rotations and positional constraints
MatrixXS M_FullSolve;
// Precomputed condensed matrices (3x3 commutators folded to 1x1):
/// Precomputed condensed matrices (3x3 commutators folded to 1x1):
MatrixXS CSM;
/// @private
MatrixXS CSolveBlock1;
// Print timings at each update
/// Print timings at each update
bool print_timings;
// Dynamics
/// dynamics
bool with_dynamics;
// I'm hiding the extra dynamics stuff in this struct, which sort of defeats
// the purpose of this function-based coding style...
// Time step
/// Time step
double h;
// L0 #handles * dim * dim+1 list of transformation entries from
// previous solve
/// #handles * dim * dim+1 list of transformation entries from
/// previous solve
MatrixXS L0;
//// Lm1 #handles * dim * dim+1 list of transformation entries from
//// previous-previous solve
//MatrixXS Lm1;
// "Velocity"
/// "Velocity"
MatrixXS Lvel0;
// #V by dim matrix of external forces
// fext
/// #V by dim matrix of external forces
MatrixXS fext;
// Mass_tilde: MT * Mass * M
/// Mass_tilde: MT * Mass * M
LbsMatrixType Mass_tilde;
// Force due to gravity (premultiplier)
/// Force due to gravity (premultiplier)
Eigen::MatrixXd fgrav;
// Direction of gravity
/// Direction of gravity
Eigen::Vector3d grav_dir;
// Magnitude of gravity
/// Magnitude of gravity
double grav_mag;
// Π1 from the paper
/// Π1 from the paper
MatrixXS Pi_1;
// Default values
// @private Default values
ArapDOFData():
energy(igl::ARAP_ENERGY_TYPE_SPOKES),
with_dynamics(false),
+21 -27
View File
@@ -45,16 +45,14 @@ IGL_INLINE void igl::arap_linear_block_spokes(
{
typedef typename MatK::Scalar Scalar;
using namespace std;
using namespace Eigen;
// simplex size (3: triangles, 4: tetrahedra)
int simplex_size = F.cols();
// Number of elements
int m = F.rows();
// Temporary output
Matrix<int,Dynamic,2> edges;
Eigen::Matrix<int ,Eigen::Dynamic,2> edges;
Kd.resize(V.rows(), V.rows());
vector<Triplet<Scalar> > Kd_IJV;
std::vector<Eigen::Triplet<Scalar> > Kd_IJV;
if(simplex_size == 3)
{
// triangles
@@ -80,7 +78,7 @@ IGL_INLINE void igl::arap_linear_block_spokes(
3,2;
}
// gather cotangent weights
Matrix<Scalar,Dynamic,Dynamic> C;
Eigen::Matrix<Scalar ,Eigen::Dynamic ,Eigen::Dynamic> C;
cotmatrix_entries(V,F,C);
// should have weights for each edge
assert(C.cols() == edges.rows());
@@ -93,10 +91,10 @@ IGL_INLINE void igl::arap_linear_block_spokes(
int source = F(i,edges(e,0));
int dest = F(i,edges(e,1));
double v = 0.5*C(i,e)*(V(source,d)-V(dest,d));
Kd_IJV.push_back(Triplet<Scalar>(source,dest,v));
Kd_IJV.push_back(Triplet<Scalar>(dest,source,-v));
Kd_IJV.push_back(Triplet<Scalar>(source,source,v));
Kd_IJV.push_back(Triplet<Scalar>(dest,dest,-v));
Kd_IJV.push_back(Eigen::Triplet<Scalar>(source,dest,v));
Kd_IJV.push_back(Eigen::Triplet<Scalar>(dest,source,-v));
Kd_IJV.push_back(Eigen::Triplet<Scalar>(source,source,v));
Kd_IJV.push_back(Eigen::Triplet<Scalar>(dest,dest,-v));
}
}
Kd.setFromTriplets(Kd_IJV.begin(),Kd_IJV.end());
@@ -112,16 +110,14 @@ IGL_INLINE void igl::arap_linear_block_spokes_and_rims(
{
typedef typename MatK::Scalar Scalar;
using namespace std;
using namespace Eigen;
// simplex size (3: triangles, 4: tetrahedra)
int simplex_size = F.cols();
// Number of elements
int m = F.rows();
// Temporary output
Kd.resize(V.rows(), V.rows());
vector<Triplet<Scalar> > Kd_IJV;
Matrix<int,Dynamic,2> edges;
std::vector<Eigen::Triplet<Scalar> > Kd_IJV;
Eigen::Matrix<int ,Eigen::Dynamic,2> edges;
if(simplex_size == 3)
{
// triangles
@@ -149,7 +145,7 @@ IGL_INLINE void igl::arap_linear_block_spokes_and_rims(
assert(false);
}
// gather cotangent weights
Matrix<Scalar,Dynamic,Dynamic> C;
Eigen::Matrix<Scalar ,Eigen::Dynamic ,Eigen::Dynamic> C;
cotmatrix_entries(V,F,C);
// should have weights for each edge
assert(C.cols() == edges.rows());
@@ -169,18 +165,18 @@ IGL_INLINE void igl::arap_linear_block_spokes_and_rims(
int Rd = F(i,edges(f,1));
if(Rs == source && Rd == dest)
{
Kd_IJV.push_back(Triplet<Scalar>(Rs,Rd,v));
Kd_IJV.push_back(Triplet<Scalar>(Rd,Rs,-v));
Kd_IJV.push_back(Eigen::Triplet<Scalar>(Rs,Rd,v));
Kd_IJV.push_back(Eigen::Triplet<Scalar>(Rd,Rs,-v));
}else if(Rd == source)
{
Kd_IJV.push_back(Triplet<Scalar>(Rd,Rs,v));
Kd_IJV.push_back(Eigen::Triplet<Scalar>(Rd,Rs,v));
}else if(Rs == dest)
{
Kd_IJV.push_back(Triplet<Scalar>(Rs,Rd,-v));
Kd_IJV.push_back(Eigen::Triplet<Scalar>(Rs,Rd,-v));
}
}
Kd_IJV.push_back(Triplet<Scalar>(source,source,v));
Kd_IJV.push_back(Triplet<Scalar>(dest,dest,-v));
Kd_IJV.push_back(Eigen::Triplet<Scalar>(source,source,v));
Kd_IJV.push_back(Eigen::Triplet<Scalar>(dest,dest,-v));
}
}
Kd.setFromTriplets(Kd_IJV.begin(),Kd_IJV.end());
@@ -195,16 +191,14 @@ IGL_INLINE void igl::arap_linear_block_elements(
MatK & Kd)
{
typedef typename MatK::Scalar Scalar;
using namespace std;
using namespace Eigen;
// simplex size (3: triangles, 4: tetrahedra)
int simplex_size = F.cols();
// Number of elements
int m = F.rows();
// Temporary output
Kd.resize(V.rows(), F.rows());
vector<Triplet<Scalar> > Kd_IJV;
Matrix<int,Dynamic,2> edges;
std::vector<Eigen::Triplet<Scalar> > Kd_IJV;
Eigen::Matrix<int ,Eigen::Dynamic,2> edges;
if(simplex_size == 3)
{
// triangles
@@ -230,7 +224,7 @@ IGL_INLINE void igl::arap_linear_block_elements(
3,2;
}
// gather cotangent weights
Matrix<Scalar,Dynamic,Dynamic> C;
Eigen::Matrix<Scalar ,Eigen::Dynamic ,Eigen::Dynamic> C;
cotmatrix_entries(V,F,C);
// should have weights for each edge
assert(C.cols() == edges.rows());
@@ -243,8 +237,8 @@ IGL_INLINE void igl::arap_linear_block_elements(
int source = F(i,edges(e,0));
int dest = F(i,edges(e,1));
double v = C(i,e)*(V(source,d)-V(dest,d));
Kd_IJV.push_back(Triplet<Scalar>(source,i,v));
Kd_IJV.push_back(Triplet<Scalar>(dest,i,-v));
Kd_IJV.push_back(Eigen::Triplet<Scalar>(source,i,v));
Kd_IJV.push_back(Eigen::Triplet<Scalar>(dest,i,-v));
}
}
Kd.setFromTriplets(Kd_IJV.begin(),Kd_IJV.end());
+66 -31
View File
@@ -10,39 +10,39 @@
#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
//
/// 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,
@@ -50,19 +50,54 @@ namespace igl
const int d,
const igl::ARAPEnergyType energy,
MatK & Kd);
// Helper functions for each energy type
/// 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,
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,
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,

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