Compare commits

...
189 Commits
Author SHA1 Message Date
Qingnan Zhou dc17178bed Minor UI tweak. 2021-01-22 10:48:29 -05:00
Qingnan Zhou f4585a8ca9 Update cgal. 2021-01-19 14:16:51 -05:00
Qingnan Zhou c5e6f66748 Add border to point. 2021-01-06 13:41:32 -05:00
Thibault LESCOAT 780a5fbea5 ImGuiTextEditCallback was renamed/deprecated in Imgui 1.63 (08/2018) 2021-01-06 06:33:07 -08:00
Alec Jacobson 61588efa78 rm min_quad_dense 2020-12-30 18:37:26 -05:00
Alec Jacobson cef9c6594f Merge branch 'master' of https://github.com/libigl/libigl 2020-12-30 18:00:18 -05:00
Alec Jacobson 9de4b6640f mv min_quad_dense --> kkt_inverse 2020-12-30 18:00:11 -05:00
Jeremie Dumas 7ebb86734a Update bin output dir on Windows. 2020-12-30 12:22:52 -08:00
alecjacobson 5b7b50c026 cmake bugs 2020-12-28 13:30:58 -05:00
Alec Jacobson aafb6870c7 fix strange logical warning 2020-12-27 18:13:05 -05:00
Alec Jacobson 4d026eeef1 Merge pull request #1653 from libigl/polygon-laplacian
polygon laplacian and other polygon functionality
2020-12-22 09:57:36 -05:00
Alec Jacobson ea57dfa2ad guess at fix of windows failure 2020-12-21 21:57:54 -05:00
Alec Jacobson 85120e557e up tut data 2020-12-21 21:31:57 -05:00
Alec Jacobson ad54f2dfe2 int->Index; depreacted pinv; trivial unit test 2020-12-21 19:53:56 -05:00
Alec Jacobson 0ac1d696f8 Merge branch 'master' of https://github.com/libigl/libigl into polygon-laplacian 2020-12-21 19:27:21 -05:00
Alec JacobsonandJérémie Dumas fbfb2d56ad Selection Plugin and Tutorial Entry (#1654)
* Selection Plugin and Tutorial Entry

* rm __1::

* templates; and dont take F as input

* missing template, fix bug

* better commenting

* windows doesn't understand M_PI

* Use ImGui::SetNextWindowSize

Co-authored-by: Jérémie Dumas <jeremie.dumas@ens-lyon.org>
2020-12-19 15:51:59 -08:00
Jérémie Dumas 858c843971 Fix nightly build + move EmbreeIntersector impl to .cpp (#1674) 2020-12-19 15:51:32 -08:00
Alec Jacobson 723eb8d74d fix readMESH issues; add test (#1679) 2020-12-19 11:09:02 -08:00
Alec Jacobson c60a948e7d remove unused mosek linking in bbw tut 2020-12-15 11:15:25 -05:00
Alec Jacobson ce32c4aa03 Merge pull request #1675 from libigl/mosek-9.2
fix mosek to work with 9.2; fix mosek dynamic link via cmake
2020-12-14 14:21:48 -05:00
Alec Jacobson e7b3e45577 missed __1:: (not in default build) 2020-12-14 14:16:43 -05:00
Alec Jacobson 7be097d585 missed __1:: (not in default build) 2020-12-13 21:09:11 -05:00
alecjacobson c47bb0507b fix compilation 2020-12-13 19:27:58 -05:00
Alec Jacobson b35d97472d fix mosek to work with 9.2; fix mosek dynamic link via cmake 2020-12-13 13:29:22 -05:00
Alec Jacobson 2ea8312e5e use angle brackets for system includes 2020-12-13 13:27:10 -05:00
Alec Jacobson f9b716fdf8 fix warning 2020-12-13 13:22:05 -05:00
Alec Jacobson c608c60a6d merge 2020-12-13 13:21:16 -05:00
Alec Jacobson 7250ea7d91 templates 2020-12-13 13:20:20 -05:00
Vladimir S. FONOV e6482a8a42 Fixed a bug in writePLY, when face properties were doubled and edge properties were dropped (#1673) 2020-12-13 10:02:31 -08:00
Alec Jacobson dbba9ca921 copyleft::marching_cubes -> marching_cubes (#1666)
* copyleft::marching_cubes -> marching_cubes

* restor imguizmo

* fix doc; lambda return type
2020-12-13 10:02:03 -08:00
Jérémie Dumas 225edb47b6 Fix typo + remove cmake warning. 2020-12-08 21:32:37 -08:00
Jérémie Dumas d14ab658df Limit to one linking job at the same time. 2020-12-08 18:45:17 -08:00
Vladimir S. FONOV c7b5d0b6e3 Offscreen meshes rendering using embree (#1652)
* Added simple raytracing renderer which allows off-screen rendering of meshes.
Using embree (already included in libigl). Addresses #1458, #601
Does not depend on OpenGL.
Tutorial example renders `fertility` example with average gaussian curvature field, in 0.1 sec.

* Separated EmbreeDevice

* Changed singleton pattern, updated variable name, removed EmbreeDevice.cpp
2020-12-08 13:26:43 -08:00
Alec Jacobson 21b62c5777 Missing normalization 2020-12-07 09:10:35 -05:00
Zhongshi f06fb13014 missing break in slim (#1641) (#1658) 2020-11-29 09:40:51 -08:00
Alec JacobsonandJérémie Dumas 59b517a4a4 bump embree version; bump sse2 to avx2 (#1648)
* bump embree version; bump sse2 to avx2

* Use default ISA instead.

* better comments

* non degenerate tests

Co-authored-by: Jérémie Dumas <jeremie.dumas@ens-lyon.org>
2020-11-29 09:40:10 -08:00
Nico efee81b7db Bump GLFW due to an error on macOS with CMake 3.19.0 (#1657) 2020-11-22 16:57:31 -08:00
Alec Jacobson bd30aa03b9 Merge branch 'master' of https://github.com/libigl/libigl 2020-11-22 13:37:11 -05:00
Alec Jacobson 49a0ab8640 templates 2020-11-22 13:37:03 -05:00
Alec Jacobson 6e1ed534ce convenience function for path extensions based on igl::pathinfo 2020-11-22 13:36:49 -05:00
Alec Jacobson 2ea66c3350 comment 2020-11-22 13:35:47 -05:00
Jérémie Dumas a3ba1f24f8 Update nightly.yml 2020-11-22 09:30:11 -08:00
Alec Jacobson 2e05e0f178 pointer bug 2020-11-20 21:13:48 -05:00
Alec Jacobson fbd4ce2399 polygon laplacian and other polygon functionality 2020-11-19 22:00:55 -05:00
Alec Jacobson 6cde8347be visible toggle for plugin 2020-11-19 10:01:24 -05:00
Jérémie Dumas 645718cf77 Update continuous.yml 2020-11-18 11:25:09 -08:00
Jérémie Dumas a956dfd37d Set env for nightly job. (#1651) 2020-11-18 10:15:42 -08:00
Jérémie Dumas 682e4b9685 Update github actions. (#1649) 2020-11-14 18:19:03 -08:00
Alec Jacobson 69b0eccb15 template 2020-11-14 15:56:27 -05:00
Alec Jacobson 03e14c609f note in .h 2020-11-14 13:25:27 -05:00
Alec Jacobson 782b7fc95d Merge branch 'master' of https://github.com/libigl/libigl 2020-11-14 13:24:52 -05:00
Alec Jacobson 55817544c2 reformat and fix crashing bugs 2020-11-14 13:24:48 -05:00
Alec Jacobson 0bb27beb88 Merge pull request #1645 from libigl/msh-in-read_triangle_mesh
support msh in read_triangle_mesh
2020-11-07 13:28:22 -05:00
Alec Jacobson dbec07d9f5 Merge pull request #1646 from libigl/matcap-tutorial
tutorial entry for matcap
2020-11-07 13:27:57 -05:00
Alec Jacobson 80711ea630 fix comment formatting causing warnings 2020-11-07 10:57:37 -05:00
Alec Jacobson c744410fe1 Merge branch 'master' of https://github.com/libigl/libigl 2020-11-07 10:56:53 -05:00
Alec Jacobson e706cc5b8b bug fix: xml::write_triangle_mesh now uses fe, too 2020-11-07 10:56:48 -05:00
Alec Jacobson 7ed7b06696 tutorial entry for matcap 2020-11-07 10:55:04 -05:00
Alec Jacobson be9b795a16 support msh in read_triangle_mesh 2020-11-07 10:49:09 -05:00
Alec Jacobson 0264736ed3 Merge pull request #1644 from HTDerekLiu/master
Update per_vertex_point_to_plane_quadrics.cpp
2020-11-05 15:17:08 -05:00
Hsueh-Ti Derek Liu a8a1216363 Update per_vertex_point_to_plane_quadrics.cpp
change boundary weight from length to length squared so that it has the same unit as face_quadric
2020-11-05 14:35:10 -05:00
Fabien Péan fb3bd3571e Update writeDAE.cpp (#1642)
Remove ambiguity (on windows) by using qualified calls everywhere.
Remove error with newer version of tinyxml2 which does not have XML_NO_ERROR
2020-11-03 15:45:05 -08:00
Fabien Péan d2bc41e99b Update orientable_patches.cpp (#1640)
Add a pair of explicit template instantiation for case where F is of type Eigen::MatrixX3i (i.e. Eigen::Matrix<int,Eigen::Dynamic,3>)
2020-11-03 15:32:25 -08:00
Kazutaka Nakashima 0a92f2cdb2 Fix bug in readSTL (#1638)
* Fix bug in readSTL

reset the position of the current character in the input

* Move seekg into the inside of if ... else ... block
2020-11-02 15:30:11 -08:00
Alec Jacobson 870eb14ec2 Update repdiag.cpp 2020-11-02 16:56:46 -05:00
Jérémie Dumas 1e905cba3d Update STL reader. (#1628)
* Update STL reader.

* Constexpr stuff.
2020-10-26 21:27:17 -07:00
Alec Jacobson 0e4e79f464 Merge pull request #1630 from daviesthomas/master
Signing distances with Fast Winding Number
2020-10-21 12:36:59 -04:00
Nico Brügel a2a1479a88 Use new gitlab remote to clone eigen. 2020-10-18 12:43:09 -07:00
Thomas Davies 51b3f7093a remove old comment 2020-10-18 12:56:03 -04:00
Thomas Davies 249f37af52 Merge remote-tracking branch 'upstream/master' into master 2020-10-18 11:19:12 -04:00
Thomas Davies 63b3669a87 test update... 2020-10-18 10:56:56 -04:00
Thomas Davies 9814e81b4b update tutorial with FWN signing option 2020-10-18 10:32:59 -04:00
Thomas Davies c21ad49c38 missing template 2020-10-18 10:04:36 -04:00
Camilo Talero d69073c329 Deletes print statement in the exact_geodesics method (#1625)
The print statement is always called, which affects debugging output of
calling libraries.
2020-10-18 00:20:47 -07:00
Alec Jacobson 8b5b424e8c fix warning (#1627) 2020-10-18 00:20:05 -07:00
Jérémie Dumas 1b745f81ed Update compiler version in github actions. (#1629) 2020-10-17 14:00:21 -07:00
Alec Jacobson fa7eb0befb Merge branch 'master' of https://github.com/libigl/libigl 2020-10-16 10:07:51 -04:00
Alec Jacobson 10c90309a8 note 2020-10-16 10:07:48 -04:00
Jérémie Dumas 062e3823c3 Make file encoding option an enum. (#1619) 2020-10-04 00:18:25 -07:00
Jérémie Dumas 7b4a19da9d Update blue_noise.cpp 2020-09-27 10:55:24 -07:00
8c95d1044e Added improved .msh reader/writer + tests + example (#1578)
* Added improved .msh reader/writer + tests + example,
with fixes proposed by @qnzhou
put append_mat_to_vec into igl::internal

* Update tutorial number.

* Changed tutorial code to use example from https://github.com/libigl/libigl-tutorial-data/pull/1 and flat shading

* Remove commented code.

* Rename tutorial number + update tutorial data.

Co-authored-by: Jérémie Dumas <jdumas@users.noreply.github.com>
Co-authored-by: Jérémie Dumas <jeremie.dumas@ens-lyon.org>
2020-09-27 10:40:29 -07:00
Jérémie Dumas 9a1ab67df9 Fix bug in random_point_on_mesh + crash with blue_noise on Windows. 2020-09-27 10:35:58 -07:00
Alec Jacobson 9921615af2 Merge pull request #1618 from libigl/ImGuizmo-simplify
move ImGuizmo tutorial into plugin; simplify and isolate
2020-09-27 11:53:07 -04:00
Oded Stein 8ea0b8c6dc Added vector Dirichlet and curved Hessian functionality (#1560)
* Added vector Dirichlet and curved Hessian functionality, as well as tutorials.

* Applied jdumas changes

* added github actions for this branch

* more jdumas changes

* Changed int to appropriate scalar

* moved around Int definition

* forgot braces somewhere

* forgot braces

* Applied changes suggested by jdumas

* forgot braces

* remove custom github workflow
2020-09-26 20:06:26 -07:00
Alec Jacobson d9864be29e move ImGuizmo tutorial into plugin; simplify and isolate 2020-09-26 15:59:28 -04:00
Alec Jacobson 28008528b4 Merge branch 'master' of https://github.com/libigl/libigl 2020-09-25 23:45:12 -04:00
Alec Jacobson 1ad4556268 fix minor issues with 109 2020-09-25 23:45:06 -04:00
Thomas Davies 35ba62b1a0 remove redundant templates 2020-09-25 23:36:46 -04:00
Thomas Davies ec24dccc29 add test case 2020-09-25 23:34:24 -04:00
Thomas Davies 1fda040670 3D only for signing with fwn 2020-09-25 23:34:06 -04:00
Thomas Davies 9bc3ffd98f Merge remote-tracking branch 'upstream/master' 2020-09-25 21:45:24 -04:00
Nico af8944c7b6 Remove deprecated functions (#1610)
* removed deprecated igl::internal_angles_using_edge_lengths()

* removed deprecated igl::is_border_vertex(V,F) and correct its templates

* removed deprecated igl::all_edges()
2020-09-20 23:21:28 -07:00
J.M. Soorya Narayan 3856ea92ce Add Kelvinlet deformations (#1614)
* Make igl::PI constexpr

* Fix typo in unproject_onto_mesh

* Add kelvinlets implementation

* Add a tutorial entry for kelvinlets
2020-09-20 23:19:24 -07:00
Alec Jacobson 91faf24015 rm buggy reserve 2020-09-18 19:25:43 -04:00
Alec Jacobson 28ab0d11de Merge pull request #1617 from libigl/blkdiag
blkdiag function
2020-09-18 16:21:53 -04:00
Alec Jacobson 5358cc5a36 __1:: 2020-09-18 14:59:15 -04:00
Alec Jacobson 775f2354fa blkdiag function 2020-09-18 14:21:20 -04:00
Alec Jacobson 9c49b73ade Merge pull request #1597 from libigl/blue-noise
Blue noise sampling on triangle meshes
2020-09-17 10:06:43 -04:00
Alec Jacobson d2a4b51e1e better doc 2020-09-16 22:27:36 -04:00
Alec Jacobson e608aad744 fix names 2020-09-16 22:26:02 -04:00
Alec Jacobson 10d2f75572 merge 2020-09-16 22:16:51 -04:00
Alec Jacobson a22ed58dc4 fix indentation 2020-09-16 22:09:07 -04:00
Alec Jacobson 4cb640737e Merge branch 'master' of https://github.com/libigl/libigl 2020-09-16 22:08:03 -04:00
Alec Jacobson 86c7c7db2e templates 2020-09-16 22:07:58 -04:00
Michael TaoandJérémie Dumas 21acee15fe making knn and octree work on more types than double, allowing knn to do nearest neighbor searches between two different point clouds (#1313)
removing a capture issue with gcc 4.8.4 in knn

Co-authored-by: Jérémie Dumas <jeremie.dumas@ens-lyon.org>
2020-09-08 07:29:12 -07:00
Jérémie Dumas eef47fe34c Merge pull request #1608 from ShuangLiu1992/patch-3
Update LibiglDownloadExternal.cmake
2020-09-07 18:49:17 -07:00
ShuangLiu1992 92dd81bb5d Update LibiglDownloadExternal.cmake
https://github.com/libigl/CoMISo/commit/d60aa4759fba76b0b793b1efb090b7a771dd7c56
2020-09-07 17:27:20 -07:00
Jérémie Dumas b42cfeba49 Merge pull request #1558 from libigl/rm-remove_duplicates
rm obsolete, poor performance, and ironically duplicate function
2020-09-07 17:11:51 -07:00
Jérémie Dumas 317f0522a8 Apt update. 2020-09-07 17:00:05 -07:00
Alec Jacobson b582ecada9 Merge pull request #1596 from libigl/rm-barycentric_to_global
rm strange function, not in use
2020-09-04 10:31:15 -04:00
Alec Jacobson bae087d7eb Merge pull request #1603 from libigl/fix-epsilon
Clarify, fix bug in epsilon parameter in remove_duplicate_vertices
2020-09-04 10:30:51 -04:00
Alec Jacobson f7067c69e9 Clarify, fix bug in epsilon parameter in remove_duplicate_vertices 2020-09-03 11:22:18 -04:00
Alec Jacobson 7db28d5700 M_PI -> igl::PI 2020-08-23 18:04:09 -04:00
Alec Jacobson 43da16bbd0 tighter test 2020-08-23 17:35:17 -04:00
Alec Jacobson 1de2627280 tests 2020-08-23 17:32:21 -04:00
Alec Jacobson c183f419e7 Merge pull request #1594 from libigl/rm-bin
rm _bin from names and use bin dir instead
2020-08-23 17:23:21 -04:00
Alec Jacobson 20924d62f1 blue noise tutorial entry 2020-08-23 16:49:34 -04:00
Alec Jacobson 48051bc889 rm strange function, not in use 2020-08-23 16:11:21 -04:00
Jérémie Dumas cb59839742 Update CMakeLists.txt 2020-08-22 13:39:40 -07:00
Alec Jacobson 4a22178717 rm _bin from names and use bin dir instead 2020-08-22 16:15:12 -04:00
Jérémie Dumas 97bd52fb52 Merge pull request #1590 from jiangzhongshi/master
move scaf to triangle folder
2020-08-22 11:12:14 -07:00
Alec Jacobson c61e28fe5a Update ViewerData.h 2020-08-21 19:47:24 -04:00
Zhongshi 07e2b01a3c move scaf to triangle folder 2020-08-17 21:16:16 -04:00
Alec Jacobson 41454f823d fix decimate bug 2020-08-15 19:49:24 -04:00
Alec Jacobson 1a4ccf65b7 Merge pull request #1554 from libigl/decimate-performance-optimization
Decimate performance optimization
2020-08-11 11:15:32 -05:00
michelleandJérémie Dumas 98a1a31641 ImGuizmo Integration (#1568)
* First working version to automatically clone ImGuizmo into libigl

* Corresponding changes to cmake files

* Moved contents of slicing plugin and menu extra to new file ImGuizmoMenu in imgui directory of igl

* Moved slicing plug into main, and ImGuizmo::EditTransform into ImGuizmoMenu which resides in igl

* Temporary hid Local and World options because they don't do anything and refactored main for tutorial 109 for clarity with some documentation

* Got orthogonal projection to render ImGuizmo normally

* Removed unecessary changes

* Removed snap parameter from ImGuizmo menu

* Added a cmake configuration for ImGuizmo

* Include imgui library in building ImGuizmo target

* Added a workflow

* Added this branch to workflow

* Update linux packages

* Explicitly include imgui header for imguizmo

* Just copy in relevant imguizmo files for now as opposed to through cmake since ImGuizmo repo does not have its own CMake file

* Conditional include to prevent mac build from failing

* Revert files for debugging cmake build

* Added build target for ImGuizmo

* Expose Imgui lib to ImGuizmo with PUBLIC interface

* Refactor build

* Get older SHA1 commit to avoid break on macOS

* Change imguizmo menu namespace

* Cleaning up + fix window border size issue.

Co-authored-by: Jérémie Dumas <jeremie.dumas@ens-lyon.org>
2020-08-10 12:00:07 -07:00
Alec Jacobson dde868d297 Merge branch 'master' of https://github.com/libigl/libigl 2020-08-09 18:00:39 -05:00
Alec Jacobson 3b80edbd7c search for mosek more 2020-08-09 18:00:29 -05:00
Alec Jacobson 7be8dc32af bump matlab versions 2020-08-09 18:00:06 -05:00
Vladimir S. FONOVandJérémie Dumas abd9f0f365 Fixed writing PLY file, when coordinates are stored as floats (#1581)
* Fixed writing PLY file, when coordinates are stored as floats

* Fix compilation.

Co-authored-by: Jérémie Dumas <jeremie.dumas@ens-lyon.org>
2020-08-09 15:55:28 -07:00
michelleandJérémie Dumas b8ee8b99cf Text Rendering Using GLSL in ImGui Menu (#1549)
* This is the code that renders the letter a for each vertex on the mesh paired with  a libigl-example-project

* Code for rendering just the number 12 on the 12th vertex

* Rendering vertices via glsl works, with geometry shader

* Added dynamic font scaling so accomodate ortho and perspective projections.

* Got faceids rendering

* Code cleanup

* This allows user to add custom text at some location rendered with the text shaders

* Dedicated separate VBOs for face and vertid labels

* Added in extra label rendering

* Moved texture binding to its own function and other code cleanup

* More conflict resolution when fetching upstream changes

* Resolved the relative path to font atlas

* Change scope variable for font atlas macro

* Removed PNG texture loaded from disk, and encoded font atlas into byte array. Other minor changes for VBO iterators and removed uneeded dependencies from previous commits

* Encapsulated text VBOs into struct to remove code duplication, and fixed bug for both overlay and text shaders being used at same time.

* Remove whitespace

* Tentative for Windows build fix not initializing TextGL structs in header

* Removed uniform that only belongs for text labels

* Added init and free methods for label buffers initialization and passing some args by reference on label methods

* Compressed font atlas that is under 50kB reduced from 330kB with decompression function

* Converting type from string literal to char array

* Broke up string literal

* Cleanup font atlas.

* Linux compile fix.

* Remove deprecated text pipeline.

Co-authored-by: Jérémie Dumas <jeremie.dumas@ens-lyon.org>
2020-08-09 15:49:22 -07:00
teseoch 45cfc79fed Viewer crash after calling clear (#1582)
missing check for empty uv similar to line 747
2020-08-07 10:04:45 -04:00
Patrick SchmidtandPatrick Schmidt 015ac35cd1 SCAF: Expose linear system to be solved by user code (#1553)
* Add const qualifiers

* Add scaf_system() and expose scaf::compute_energy()

* Add test "scaf_system"

Co-authored-by: Patrick Schmidt <patrick.schmidt@cs.rwth-aachen.de>
2020-07-06 07:36:59 -07:00
Alec Jacobson d95f3a410f stupid __1 junk 2020-06-30 14:26:07 -04:00
Alec Jacobson 3a110bbf4d rm obsolete, poor performance, and ironically duplicate function 2020-06-30 12:46:28 -04:00
Alec Jacobson ac56a694f2 return # comps 2020-06-30 10:43:29 -04:00
Alec Jacobson a3c3ef1572 update test too 2020-06-30 10:42:50 -04:00
Alec Jacobson b03769f26e template issue 2020-06-30 10:27:35 -04:00
Alec Jacobson 1b53e54815 rm F, dense W 2020-06-30 10:19:10 -04:00
Alec Jacobson d22414e388 func -> callback, always_... -> trivial 2020-06-29 12:10:10 -04:00
Alec Jacobson 005ae90b67 better name for always try never care defaults 2020-06-28 11:25:29 -04:00
Alec Jacobson 39c7d33b4c missing includes/templates 2020-06-27 21:17:35 -04:00
Alec Jacobson 61834f4fa1 separate header for header-only mode circular deps 2020-06-27 21:02:19 -04:00
Alec Jacobson d3248f0a0f performance improvements for decimate 2020-06-27 20:43:55 -04:00
Alec Jacobson 7ee863c92f 'using' to define function handle types 2020-06-27 17:09:36 -04:00
Alec Jacobson 58a600aebf Merge branch 'master' of https://github.com/libigl/libigl 2020-06-25 15:21:25 -04:00
Alec Jacobson 95a7b15efc Merge branch 'Dxyk-direct-delta-mush' 2020-06-25 15:21:15 -04:00
Alec Jacobson ae5d163f7d elephant data 2020-06-25 15:19:46 -04:00
Dxyk 8268a3f33b direct delta mush build fix 2020-06-22 17:57:52 -04:00
Dxyk e4ab356031 direct delta mush review fix and unit test 2020-06-22 17:26:11 -04:00
michelle 762a4ec1f4 ImGui Update to v1.76 (#1545) 2020-06-14 20:17:59 -07:00
DarioSamo 238d52c90f Address memory heap corruption on Windows open dialog on long filenames (#1544)
fixes #1513
2020-06-14 17:14:16 -07:00
Jérémie Dumas 1e78a3473a Merge pull request #1546 from DarioSamo/tutorial-patch
Add 719_ExplodedView to tutorials folder.
2020-06-12 18:25:55 -07:00
Dario 3b0ec3ce63 Add 719_ExplodedView to tutorials folder. 2020-06-12 20:13:01 -03:00
Alec Jacobson d22f873ef2 missing template 2020-06-11 12:04:14 -04:00
Dxyk ce201a7433 direct delta mush implicit method 2020-06-09 18:12:52 -04:00
Jérémie Dumas 48a7e8cd02 Merge pull request #1538 from bbrrck/master
Fix compilation error with Eigen 3.3+
2020-06-05 07:20:41 -07:00
Dxyk feb71ef502 direct delta mush fix build 2020-06-04 18:56:36 -04:00
Dxyk dc01d7e277 Merge branch 'master' of https://github.com/libigl/libigl into direct-delta-mush 2020-06-04 18:11:43 -04:00
Dxyk 75a0c4fa2c direct delta mush bug fixes 2020-06-04 18:10:58 -04:00
teseoch 60ffe1b0dc Python (#1453)
fixing templates for python bindings.
2020-06-04 12:49:06 -04:00
Tibor Stanko 0b52794637 Fix compilation error with Eigen 3.3+
Fixes the error "incompatible operand types" when libigl is compiled with Eigen 3.3+.
2020-06-04 11:50:49 +02:00
Dxyk 71e65516ae use 10 floats 2020-05-30 20:27:40 -04:00
Dxyk 3f67752504 update diagonal inverse 2020-05-28 21:37:30 -04:00
Dxyk 95a80d3fa9 computation done 2020-05-27 16:04:58 -04:00
Dxyk 5f72004d0d precomputation assert 2020-05-26 14:23:34 -04:00
Dxyk b0a8fa84e1 Merge branch 'master' of https://github.com/libigl/libigl into direct-delta-mush 2020-05-25 15:13:58 -04:00
Dxyk 162f9b8f68 precomputation done 2020-05-25 15:13:43 -04:00
Jérémie Dumas 32e3edf229 Merge pull request #1525 from bvoq/patch-1
Fixed load_mesh for obj
2020-05-24 09:32:56 -07:00
Zhongshi f3a201f1e1 Update heat_geodesics.cpp (#1512)
* Update heat_geodesics.cpp

* heat geodesic upsampled cube unit test
2020-05-24 09:31:16 -07:00
Dxyk 916a5c217d precomputation without vector form 2020-05-21 22:53:14 -04:00
Dxyk 3141dfc26d precomputation - W 2020-05-21 15:34:35 -04:00
Kevin De Keyser 14d6bcec3d Fixed load_mesh for obj 2020-05-21 17:06:13 +02:00
Dxyk 6eb02be7db direct delta mush tutorial 2020-05-19 16:21:42 -04:00
Thomas 3da9d323fb Merge pull request #1 from daviesthomas/fast_winding_signed_distance
Fast winding signed distance
2020-05-18 11:32:48 -04:00
Zhongshi c7324d3fa6 Update remove_duplicate_vertices.h (#1514) 2020-05-17 19:29:33 -07:00
Dxyk ae903ae468 direct delta mush init 2020-05-17 14:05:58 -04:00
Jérémie Dumas 3069260f07 Update README.md 2020-05-15 17:46:01 -07:00
Kenneth BlomqvistandJérémie Dumas 1df0987271 Fix issue with dijkstra algorithm (#1497)
* Use ::max vs ::infinity in dijkstra

* Add test case for discrete dijkstra distances

* Update dijkstra.cpp

* Explicit template instantiation for dijkstra test

Co-authored-by: Jérémie Dumas <jdumas@users.noreply.github.com>
2020-05-14 07:39:36 -07:00
Alec Jacobson ce9b23e8b9 Merge pull request #1510 from libigl/exploded-view
exploded view of tetrahedral meshes
2020-05-08 12:13:39 -04:00
Thomas Davies e2548f971c python bindings for signed_distance with fast_winding_number 2019-10-24 13:06:24 -04:00
Thomas Davies 6983cfd1f4 explicit templating 2019-10-24 11:06:01 -04:00
Thomas Davies 2f570a0e97 signed distance from pre computed fast winding number bvh 2019-10-21 13:02:49 -04:00
Thomas Davies edb21bef2c rename fast winding tree for clarity 2019-10-21 10:11:33 -04:00
Thomas Davies 48e3c72dfe fast winding number signed distance function
added dedicted functions to fast winding number for fast inference from pre computed AABB tree and BVH
2019-10-21 10:09:54 -04:00
Thomas Davies d7dd3c2356 expose fast winding in python bindings 2019-10-19 11:42:31 -04:00
Thomas Davies 61878ade62 fast winding for signing distance 2019-10-14 18:45:08 -04:00
Thomas Davies 3404ee671b fast winding number computation of single point 2019-10-13 21:32:35 -04:00
Thomas Davies 21d95881ed Merge branch 'fast-winding-number-soups' of https://github.com/daviesthomas/libigl 2019-10-12 10:45:03 -04:00
361 changed files with 14312 additions and 4746 deletions
+19 -16
View File
@@ -25,13 +25,13 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-18.04, macos-latest]
os: [ubuntu-20.04, macos-latest]
config: [Release]
static: [ON, OFF]
include:
- os: macos-latest
name: macOS
- os: ubuntu-18.04
- os: ubuntu-20.04
name: Linux
env:
LIBIGL_NUM_THREADS: 1 # See https://github.com/libigl/libigl/pull/996
@@ -44,16 +44,17 @@ jobs:
- name: Dependencies (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install \
libblas-dev \
libboost-filesystem-dev \
libboost-system-dev \
libboost-thread-dev \
libglu1-mesa-dev \
liblapack-dev \
libmpfr-dev \
xorg-dev \
ccache
libblas-dev \
libboost-filesystem-dev \
libboost-system-dev \
libboost-thread-dev \
libglu1-mesa-dev \
liblapack-dev \
libmpfr-dev \
xorg-dev \
ccache
- name: Dependencies (macOS)
if: runner.os == 'macOS'
@@ -109,11 +110,10 @@ jobs:
fetch-depth: 10
- uses: seanmiddleditch/gha-setup-ninja@master
# https://github.com/actions/cache/issues/101
- name: Set env
run: |
echo "::set-env name=appdata::$($env:LOCALAPPDATA)"
echo "::set-env name=BOOST_ROOT::$env:BOOST_ROOT_1_69_0"
echo "BOOST_ROOT=$env:BOOST_ROOT_1_72_0" >> ${env:GITHUB_ENV}
echo "appdata=$env:LOCALAPPDATA" >> ${env:GITHUB_ENV}
- name: Cache build
id: cache-build
@@ -126,8 +126,8 @@ jobs:
run: |
Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')
scoop install sccache --global
# Scoop modifies the PATH so we make the modified PATH global.
echo "::set-env name=PATH::$env:PATH"
# Scoop modifies the PATH so we make it available for the next steps of the job
echo "${env:PATH}" >> ${env:GITHUB_PATH}
# We run configure + build in the same step, since they both need to call VsDevCmd
# Also, cmd uses ^ to break commands into multiple lines (in powershell this is `)
@@ -141,6 +141,9 @@ jobs:
-DLIBIGL_USE_STATIC_LIBRARY=${{ matrix.static }} ^
-DLIBIGL_WITH_CGAL=ON ^
-DLIBIGL_WITH_COMISO=OFF ^
-DCMAKE_JOB_POOLS=pool-linking=1;pool-compilation=2 ^
-DCMAKE_JOB_POOL_COMPILE:STRING=pool-compilation ^
-DCMAKE_JOB_POOL_LINK:STRING=pool-linking ^
-B build ^
-S .
cmake --build build
+32 -33
View File
@@ -23,47 +23,47 @@ jobs:
fail-fast: false
matrix:
name: [
ubuntu-18.04-gcc-7,
ubuntu-18.04-gcc-8,
ubuntu-18.04-gcc-9,
ubuntu-18.04-clang-7,
ubuntu-18.04-clang-8,
ubuntu-18.04-clang-9,
ubuntu-20.04-gcc-8,
ubuntu-20.04-gcc-9,
ubuntu-20.04-gcc-10,
ubuntu-20.04-clang-8,
ubuntu-20.04-clang-9,
ubuntu-20.04-clang-10,
macOS-latest,
]
config: [Debug, Release]
static: [ON, OFF]
include:
- name: ubuntu-18.04-gcc-7
os: ubuntu-18.04
compiler: gcc
version: "7"
- name: ubuntu-18.04-gcc-8
os: ubuntu-18.04
- name: ubuntu-20.04-gcc-8
os: ubuntu-20.04
compiler: gcc
version: "8"
- name: ubuntu-18.04-gcc-9
os: ubuntu-18.04
- name: ubuntu-20.04-gcc-9
os: ubuntu-20.04
compiler: gcc
version: "9"
- name: ubuntu-18.04-clang-7
os: ubuntu-18.04
compiler: clang
version: "7"
- name: ubuntu-20.04-gcc-10
os: ubuntu-20.04
compiler: gcc
version: "10"
- name: ubuntu-18.04-clang-8
os: ubuntu-18.04
- name: ubuntu-20.04-clang-8
os: ubuntu-20.04
compiler: clang
version: "8"
- name: ubuntu-18.04-clang-9
os: ubuntu-18.04
- name: ubuntu-20.04-clang-9
os: ubuntu-20.04
compiler: clang
version: "9"
- name: ubuntu-20.04-clang-10
os: ubuntu-20.04
compiler: clang
version: "10"
- name: macOS-latest
os: macOS-latest
@@ -84,20 +84,16 @@ jobs:
- name: Dependencies (Linux)
if: runner.os == 'Linux'
run: |
# LLVM 9 is not in Bionic's repositories so we add the official LLVM repository.
if [ "${{ matrix.compiler }}" = "clang" ] && [ "${{ matrix.version }}" = "9" ]; then
sudo add-apt-repository "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main"
fi
sudo apt-get update
if [ "${{ matrix.compiler }}" = "gcc" ]; then
sudo apt-get install -y g++-${{ matrix.version }}
echo "::set-env name=CC::gcc-${{ matrix.version }}"
echo "::set-env name=CXX::g++-${{ matrix.version }}"
echo "CC=gcc-${{ matrix.version }}" >> $GITHUB_ENV
echo "CXX=g++-${{ matrix.version }}" >> $GITHUB_ENV
else
sudo apt-get install -y clang-${{ matrix.version }}
echo "::set-env name=CC::clang-${{ matrix.version }}"
echo "::set-env name=CXX::clang++-${{ matrix.version }}"
echo "CC=clang-${{ matrix.version }}" >> $GITHUB_ENV
echo "CXX=clang++-${{ matrix.version }}" >> $GITHUB_ENV
fi
sudo apt-get install \
@@ -168,7 +164,7 @@ jobs:
- name: Set env
run: |
echo "::set-env name=BOOST_ROOT::$env:BOOST_ROOT_1_69_0"
echo "BOOST_ROOT=$env:BOOST_ROOT_1_72_0" >> ${env:GITHUB_ENV}
# We run configure + build in the same step, since they both need to call VsDevCmd
# Also, cmd uses ^ to break commands into multiple lines (in powershell this is `)
@@ -182,9 +178,12 @@ jobs:
-DLIBIGL_BUILD_TUTORIALS=${{ matrix.tutorials }} ^
-DLIBIGL_WITH_CGAL=ON ^
-DLIBIGL_WITH_COMISO=OFF ^
-DCMAKE_JOB_POOLS=pool-linking=1;pool-compilation=2 ^
-DCMAKE_JOB_POOL_COMPILE:STRING=pool-compilation ^
-DCMAKE_JOB_POOL_LINK:STRING=pool-linking ^
-B build ^
-S .
cmake --build build -j 2
cmake --build build -j 1
- name: Tests
run: cd build; ctest --verbose
+1
View File
@@ -97,3 +97,4 @@ tutorial/cmake-build-debug
tutorial/data
tutorial/readme.html
untitled
scripts
+2 -1
View File
@@ -1,5 +1,6 @@
# libigl - A simple C++ geometry processing library
[![](https://github.com/libigl/libigl/workflows/Build/badge.svg)](https://github.com/libigl/libigl/actions)
[![](https://github.com/libigl/libigl/workflows/Build/badge.svg?event=push)](https://github.com/libigl/libigl/actions?query=workflow%3ABuild+branch%3Amaster+event%3Apush)
[![](https://github.com/libigl/libigl/workflows/Nightly/badge.svg)](https://github.com/libigl/libigl/actions?query=workflow%3ANightly+branch%3Amaster+event%3Aschedule)
[![](https://anaconda.org/conda-forge/igl/badges/installer/conda.svg)](https://anaconda.org/conda-forge/igl)
![](https://libigl.github.io/libigl-teaser.png)
+1 -1
View File
@@ -1,7 +1,7 @@
# Distributed under the OSI-approved MIT License. See accompanying
# file LICENSE or https://github.com/Crascit/DownloadProject for details.
cmake_minimum_required(VERSION 2.8.2)
cmake_minimum_required(VERSION 3.1)
project(${DL_ARGS_PROJ}-download NONE)
+7
View File
@@ -224,7 +224,14 @@ if(NOT MATLAB_ADDITIONAL_VERSIONS)
set(MATLAB_ADDITIONAL_VERSIONS)
endif()
# Is this mapping necessary? It's always causing trouble to need to bump these
# for each new version.
set(MATLAB_VERSIONS_MAPPING
"R2020b=9.9"
"R2020a=9.8"
"R2019b=9.7"
"R2019a=9.6"
"R2018b=9.5"
"R2018a=9.4"
"R2017b=9.3"
"R2017a=9.2"
+2
View File
@@ -9,8 +9,10 @@
# Hardcoded search paths
set(SEARCH_PATHS
${CMAKE_SOURCE_DIR}/mosek/9.2/tools/platform/osx64x86/
/usr/local/mosek/7/tools/platform/osx64x86/
/usr/local/mosek/8/tools/platform/osx64x86/
/usr/local/mosek/9.2/tools/platform/osx64x86/
/opt/mosek/7/tools/platform/linux64x86/
)
+20 -12
View File
@@ -43,7 +43,7 @@ endfunction()
function(igl_download_cgal)
igl_download_project(cgal
GIT_REPOSITORY https://github.com/CGAL/cgal.git
GIT_TAG f7c3c8212b56c0d6dae63787efc99093f4383415
GIT_TAG v5.2
)
endfunction()
@@ -51,7 +51,7 @@ endfunction()
function(igl_download_comiso)
igl_download_project(CoMISo
GIT_REPOSITORY https://github.com/libigl/CoMISo.git
GIT_TAG 1f9618cf9b7bd77370d817976470d59091928606
GIT_TAG d60aa4759fba76b0b793b1efb090b7a771dd7c56
)
endfunction()
@@ -67,7 +67,7 @@ endfunction()
set(LIBIGL_EIGEN_VERSION 3.3.7 CACHE STRING "Default version of Eigen used by libigl.")
function(igl_download_eigen)
igl_download_project(eigen
GIT_REPOSITORY https://github.com/eigenteam/eigen-git-mirror.git
GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
GIT_TAG ${LIBIGL_EIGEN_VERSION}
${LIBIGL_BRANCH_OPTIONS}
)
@@ -77,7 +77,7 @@ endfunction()
function(igl_download_embree)
igl_download_project(embree
GIT_REPOSITORY https://github.com/embree/embree.git
GIT_TAG v3.5.2
GIT_TAG v3.12.1
${LIBIGL_BRANCH_OPTIONS}
)
endfunction()
@@ -94,7 +94,7 @@ endfunction()
function(igl_download_glfw)
igl_download_project(glfw
GIT_REPOSITORY https://github.com/glfw/glfw.git
GIT_TAG 3.3
GIT_TAG 3327050ca66ad34426a82c217c2d60ced61526b7
${LIBIGL_BRANCH_OPTIONS}
)
endfunction()
@@ -103,12 +103,21 @@ endfunction()
function(igl_download_imgui)
igl_download_project(imgui
GIT_REPOSITORY https://github.com/ocornut/imgui.git
GIT_TAG v1.69
GIT_TAG v1.76
${LIBIGL_BRANCH_OPTIONS}
)
igl_download_project(libigl-imgui
GIT_REPOSITORY https://github.com/libigl/libigl-imgui.git
GIT_TAG 07ecd3858acc71e70f0f9b2dea20a139bdddf8ae
GIT_TAG 99f0643089b19f6daf5b3efd9544a65c9a851966
)
endfunction()
## ImGuizmo
function(igl_download_imguizmo)
igl_download_project(imguizmo
GIT_REPOSITORY https://github.com/CedricGuillemet/ImGuizmo.git
GIT_TAG a23567269f6617342bcc112394bdad937b54b2d7
${LIBIGL_BRANCH_OPTIONS}
)
endfunction()
@@ -148,7 +157,7 @@ endfunction()
function(igl_download_triangle)
igl_download_project(triangle
GIT_REPOSITORY https://github.com/libigl/triangle.git
GIT_TAG d284c4a843efac043c310f5fa640b17cf7d96170
GIT_TAG 5a70326574b34d6a51d9eaf6a9f78813657ee108
)
endfunction()
@@ -164,7 +173,7 @@ endfunction()
function(igl_download_predicates)
igl_download_project(predicates
GIT_REPOSITORY https://github.com/libigl/libigl-predicates.git
GIT_TAG 5a1d2194ec114bff51d5a33230586cafb83adc86
GIT_TAG 488242fa2b1f98a9c5bd1441297fb4a99a6a9ae4
)
endfunction()
@@ -175,7 +184,7 @@ function(igl_download_test_data)
igl_download_project_aux(test_data
"${LIBIGL_EXTERNAL}/../tests/data"
GIT_REPOSITORY https://github.com/libigl/libigl-tests-data
GIT_TAG b5dddf45e329af685cd107e38770a28cfc18eb15
GIT_TAG 19cedf96d70702d8b3a83eb27934780c542356fe
)
endfunction()
@@ -184,7 +193,6 @@ function(igl_download_tutorial_data)
igl_download_project_aux(tutorial_data
"${LIBIGL_EXTERNAL}/../tutorial/data"
GIT_REPOSITORY https://github.com/libigl/libigl-tutorial-data
GIT_TAG 5c6a1ea809c043d71e5595775709c15325a7158c
GIT_TAG c1f9ede366d02e3531ecbaec5e3769312f31cccd
)
endfunction()
+2
View File
@@ -82,6 +82,7 @@ igl_folder_targets("Tutorials"
405_AsRigidAsPossible_bin
406_FastAutomaticSkinningTransformations_bin
407_BiharmonicCoordinates_bin
408_DirectDeltaMush_bin
501_HarmonicParam_bin
502_LSCMParam_bin
503_ARAPParam_bin
@@ -111,6 +112,7 @@ igl_folder_targets("Tutorials"
715_MeshImplicitFunction_bin
716_HeatGeodesics_bin
718_IterativeClosestPoint_bin
719_ExplodedView_bin
)
endfunction()
+151
View File
@@ -0,0 +1,151 @@
# OS X requires a Mach-O dynamic library to have a baked "install name", that is used by other modules to link to it. Depending
# on how the library is built, the install name is not always an absolute path, nor necessarily the same as the name of the
# library file itself. This macro takes as input the name of a target, and a list of libraries that it links to (the output of
# FIND_PACKAGE or FIND_LIBRARY calls), and generates a set of custom, post-build commands that, for each linked dylib, changes
# the name the target uses to refer to it with a fully-qualified (absolute) version of the library's own install name. This
# helps ensure that the target can be used from any location while still being able to locate the linked dynamic libraries.
#
# Note that this script does NOT handle the case when a linked library itself refers to another library using a non-absolute
# name (Boost is a notorious example). To avoid such issues, it is recommended to use a static library instead of a shared one
# in a non-standard location. Alternatively, set DYLD_LIBRARY_PATH to include these non-standard locations when running the
# program (not recommended).
#
# Author: Siddhartha Chaudhuri, 2009.
#
# Set the minimum required CMake version
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
# See cmake --help-policy CMP0011 for details on this one
IF(POLICY CMP0011)
CMAKE_POLICY(SET CMP0011 NEW)
ENDIF(POLICY CMP0011)
# See cmake --help-policy CMP0026 for details on this one
IF(POLICY CMP0026)
CMAKE_POLICY(SET CMP0026 NEW)
ENDIF(POLICY CMP0026)
# See cmake --help-policy CMP0045 for details on this one
IF(POLICY CMP0045)
CMAKE_POLICY(SET CMP0045 NEW)
ENDIF(POLICY CMP0045)
MACRO(OSX_FIX_DYLIB_REFERENCES target libraries)
IF(APPLE)
SET(OFIN_${target}_RPATHS )
FOREACH(OFIN_${target}_Library ${libraries})
IF(${OFIN_${target}_Library} MATCHES "[.]dylib$"
OR ${OFIN_${target}_Library} MATCHES "[.]framework/.+")
# Resolve symlinks and get absolute location
GET_FILENAME_COMPONENT(OFIN_${target}_LibraryAbsolute ${OFIN_${target}_Library} ABSOLUTE)
# Get the baked install name of the library
EXECUTE_PROCESS(COMMAND otool -D ${OFIN_${target}_LibraryAbsolute}
OUTPUT_VARIABLE OFIN_${target}_LibraryInstallNameOutput
OUTPUT_STRIP_TRAILING_WHITESPACE)
STRING(REGEX REPLACE "[\r\n]" " " OFIN_${target}_LibraryInstallNameOutput ${OFIN_${target}_LibraryInstallNameOutput})
SEPARATE_ARGUMENTS(OFIN_${target}_LibraryInstallNameOutput)
LIST(GET OFIN_${target}_LibraryInstallNameOutput 1 OFIN_${target}_LibraryInstallName)
IF(${OFIN_${target}_LibraryInstallName} MATCHES "^[@]rpath/")
# Ideally, we want to eliminate the longest common suffix of the install name and the absolute path. Whatever's left
# will be the desired rpath. But this is difficult to do (especially if there are naming variations, e.g.
# "Versions/Current" vs "Versions/5" is a common culprit). So we'll add various candidate rpaths and hope at least one
# is correct.
# Typically, the rpath to a library within a framework looks like this:
# @rpath/A.framework/Versions/5/libFoo.dylib
#
# Hence, we'll extract for the path unit immediately following the @rpath (in this case A.framework) and then look for
# it in the library's actual path. Everything before this location will be put in the rpath.
SET(OFIN_${target}_PathPrefix ${OFIN_${target}_LibraryInstallName})
SET(OFIN_${target}_RpathFirstChild )
WHILE(NOT OFIN_${target}_PathPrefix STREQUAL "@rpath")
GET_FILENAME_COMPONENT(OFIN_${target}_RpathFirstChild ${OFIN_${target}_PathPrefix} NAME)
GET_FILENAME_COMPONENT(OFIN_${target}_PathPrefix ${OFIN_${target}_PathPrefix} PATH)
IF(NOT OFIN_${target}_PathPrefix) # should never happen but just in case
BREAK()
ENDIF(NOT OFIN_${target}_PathPrefix)
IF(OFIN_${target}_PathPrefix STREQUAL "/") # should never happen but just in case
BREAK()
ENDIF(OFIN_${target}_PathPrefix STREQUAL "/")
ENDWHILE(NOT OFIN_${target}_PathPrefix STREQUAL "@rpath")
IF(OFIN_${target}_RpathFirstChild)
SET(OFIN_${target}_PathPrefix ${OFIN_${target}_LibraryAbsolute})
SET(OFIN_${target}_PathUnit )
WHILE(NOT OFIN_${target}_PathUnit STREQUAL ${OFIN_${target}_RpathFirstChild})
GET_FILENAME_COMPONENT(OFIN_${target}_PathUnit ${OFIN_${target}_PathPrefix} NAME)
GET_FILENAME_COMPONENT(OFIN_${target}_PathPrefix ${OFIN_${target}_PathPrefix} PATH)
IF(NOT OFIN_${target}_PathPrefix)
BREAK()
ENDIF(NOT OFIN_${target}_PathPrefix)
IF(OFIN_${target}_PathPrefix STREQUAL "/")
BREAK()
ENDIF(OFIN_${target}_PathPrefix STREQUAL "/")
ENDWHILE(NOT OFIN_${target}_PathUnit STREQUAL ${OFIN_${target}_RpathFirstChild})
IF(OFIN_${target}_PathPrefix)
SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${OFIN_${target}_PathPrefix}")
ENDIF(OFIN_${target}_PathPrefix)
ENDIF(OFIN_${target}_RpathFirstChild)
# Add the directory containing the library
GET_FILENAME_COMPONENT(OFIN_${target}_LibraryAbsolutePath ${OFIN_${target}_LibraryAbsolute} PATH)
SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${OFIN_${target}_LibraryAbsolutePath}")
# Add paths specified as library search prefixes
FOREACH(prefix ${CMAKE_PREFIX_PATH})
SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${CMAKE_PREFIX_PATH}")
SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${CMAKE_PREFIX_PATH}/lib")
ENDFOREACH()
ELSEIF(NOT ${OFIN_${target}_LibraryInstallName} MATCHES "^[@/]") # just a relative path
# Replace the unqualified filename, if it appears, with the absolute location, either by directly changing the path or
# by editing the rpath
# -- handle the case when the actual filename is baked in
GET_FILENAME_COMPONENT(OFIN_${target}_LibraryFilename ${OFIN_${target}_LibraryAbsolute} NAME)
ADD_CUSTOM_COMMAND(TARGET ${target} POST_BUILD
COMMAND install_name_tool
ARGS -change
${OFIN_${target}_LibraryFilename}
${OFIN_${target}_LibraryAbsolute}
$<TARGET_FILE:${target}>)
# -- handle the case when the install name is baked in
ADD_CUSTOM_COMMAND(TARGET ${target} POST_BUILD
COMMAND install_name_tool
ARGS -change
${OFIN_${target}_LibraryInstallName}
${OFIN_${target}_LibraryAbsolute}
$<TARGET_FILE:${target}>)
ENDIF()
ENDIF()
ENDFOREACH(OFIN_${target}_Library)
# Add the collected rpaths
IF(OFIN_${target}_RPATHS)
LIST(REMOVE_DUPLICATES OFIN_${target}_RPATHS)
FOREACH(rpath ${OFIN_${target}_RPATHS})
ADD_CUSTOM_COMMAND(TARGET ${target} POST_BUILD
COMMAND bash
ARGS -c "install_name_tool -add_rpath '${rpath}' '$<TARGET_FILE:${target}>' > /dev/null 2>&1 || true"
VERBATIM)
ENDFOREACH()
ENDIF()
ENDIF()
ENDMACRO(OSX_FIX_DYLIB_REFERENCES)
+9 -2
View File
@@ -301,11 +301,12 @@ if(LIBIGL_WITH_EMBREE)
if(NOT TARGET embree)
igl_download_embree()
# Note: On macOS, building embree as a static lib can only be done with a single ISA target.
set(EMBREE_MAX_ISA "DEFAULT" CACHE STRING "Selects highest ISA to support.")
set(EMBREE_TESTING_INTENSITY 0 CACHE STRING "")
set(EMBREE_ISPC_SUPPORT OFF CACHE BOOL " ")
set(EMBREE_TASKING_SYSTEM "INTERNAL" CACHE BOOL " ")
set(EMBREE_TUTORIALS OFF CACHE BOOL " ")
set(EMBREE_MAX_ISA "SSE2" CACHE STRING " ")
set(EMBREE_STATIC_LIB ON CACHE BOOL " ")
if(MSVC)
set(EMBREE_STATIC_RUNTIME ${IGL_STATIC_RUNTIME} CACHE BOOL "Use the static version of the C/C++ runtime library.")
@@ -398,7 +399,13 @@ if(LIBIGL_WITH_OPENGL_GLFW_IMGUI)
igl_download_imgui()
add_subdirectory(${LIBIGL_EXTERNAL}/libigl-imgui imgui)
endif()
target_link_libraries(igl_opengl_glfw_imgui ${IGL_SCOPE} igl_opengl_glfw imgui)
if(NOT TARGET imguizmo)
igl_download_imguizmo()
add_library(imguizmo ${LIBIGL_EXTERNAL}/imguizmo/ImGuizmo.cpp ${LIBIGL_EXTERNAL}/imguizmo/ImGuizmo.h)
target_compile_features(imguizmo PUBLIC cxx_std_11)
target_link_libraries(imguizmo PUBLIC imgui)
endif()
target_link_libraries(igl_opengl_glfw_imgui ${IGL_SCOPE} igl_opengl_glfw imgui imguizmo)
endif()
endif()
+35 -55
View File
@@ -1025,64 +1025,44 @@ namespace igl
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template double igl::AABB<Eigen::Matrix<double, -1, 3, 1, -1, 3>, 3>::squared_distance<Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, double, double, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&) const;
template void igl::AABB<Eigen::Matrix<double, -1, 3, 1, -1, 3>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&) const;
// generated by autoexplicit.sh
template void igl::AABB<Eigen::Matrix<double, -1, 3, 1, -1, 3>, 3>::init<Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&);
// generated by autoexplicit.sh
// generated by autoexplicit.sh
template float igl::AABB<Eigen::Matrix<float, -1, 3, 0, -1, 3>, 3>::squared_distance<Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::Matrix<float, 1, 3, 1, 1, 3> const&, float, float, int&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&) const;
// generated by autoexplicit.sh
// generated by autoexplicit.sh
template void igl::AABB<Eigen::Matrix<float, -1, 3, 0, -1, 3>, 3>::init<Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&);
// generated by autoexplicit.sh
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::serialize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, int) const;
// generated by autoexplicit.sh
template std::vector<int, std::allocator<int> > igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::find<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 1, -1, 1, 1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, bool) const;
// generated by autoexplicit.sh
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::serialize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, int) const;
// generated by autoexplicit.sh
template std::vector<int, std::allocator<int> > igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::find<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 1, -1, 1, 1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, bool) const;
// generated by autoexplicit.sh
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::init<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<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int);
// generated by autoexplicit.sh
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::init<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<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int);
// generated by autoexplicit.sh
template float igl::AABB<Eigen::Matrix<float, -1, 3, 1, -1, 3>, 3>::squared_distance<Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<float, 1, 3, 1, 1, 3> const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&) const;
// generated by autoexplicit.sh
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<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<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
// generated by autoexplicit.sh
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<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<long, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&) const;
// generated by autoexplicit.sh
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<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<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
// generated by autoexplicit.sh
template double igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&) const;
// generated by autoexplicit.sh
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<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<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
// generated by autoexplicit.sh
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<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<long, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&) const;
// generated by autoexplicit.sh
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<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<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
// generated by autoexplicit.sh
template double igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 2, 1, 1, 2> const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&) const;
// generated by autoexplicit.sh
template void igl::AABB<Eigen::Matrix<float, -1, 3, 1, -1, 3>, 3>::init<Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&);
// generated by autoexplicit.sh
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::init<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
// generated by autoexplicit.sh
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::init<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
template double igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, double, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&) const;
template void igl::AABB<Eigen::Matrix<double, -1, 3, 1, -1, 3>, 3>::init<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
template bool igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::intersect_ray<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, igl::Hit&) const;
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 2, 3, 0, 2, 3>, Eigen::Matrix<double, 2, 1, 0, 2, 1>, Eigen::Matrix<int, 2, 1, 0, 2, 1>, Eigen::Matrix<double, 2, 3, 0, 2, 3> >(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, 2, 3, 0, 2, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 2, 1, 0, 2, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 3, 0, 2, 3> >&) const;
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<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<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<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<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<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<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::init<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&);
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::init<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&);
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<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<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<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<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
template double igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 2, 1, 1, 2> const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&) const;
template double igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, double, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&) const;
template double igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&) const;
template double igl::AABB<Eigen::Matrix<double, -1, 3, 1, -1, 3>, 3>::squared_distance<Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, double, double, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&) const;
template float igl::AABB<Eigen::Matrix<float, -1, 3, 0, -1, 3>, 3>::squared_distance<Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::Matrix<float, 1, 3, 1, 1, 3> const&, float, float, int&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&) const;
template float igl::AABB<Eigen::Matrix<float, -1, 3, 1, -1, 3>, 3>::squared_distance<Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<float, 1, 3, 1, 1, 3> const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&) const;
template std::vector<int, std::allocator<int> > igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::find<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 1, -1, 1, 1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, bool) const;
template std::vector<int, std::allocator<int> > igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::find<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> >(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::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, bool) const;
template std::vector<int, std::allocator<int> > igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::find<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 1, -1, 1, 1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, bool) const;
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::init<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::init<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<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int);
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::init<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&);
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::serialize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, int) const;
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<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<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<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<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<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<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<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<long, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&) const;
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<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<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::init<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::init<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<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int);
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::init<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&);
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::serialize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, int) const;
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<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<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<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<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<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<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<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<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<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<long, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&) const;
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 2, 3, 0, 2, 3>, Eigen::Matrix<double, 2, 1, 0, 2, 1>, Eigen::Matrix<int, 2, 1, 0, 2, 1>, Eigen::Matrix<double, 2, 3, 0, 2, 3> >(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, 2, 3, 0, 2, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 2, 1, 0, 2, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 3, 0, 2, 3> >&) const;
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<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<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
template void igl::AABB<Eigen::Matrix<double, -1, 3, 1, -1, 3>, 3>::init<Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&);
template void igl::AABB<Eigen::Matrix<float, -1, 3, 0, -1, 3>, 3>::init<Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&);
template void igl::AABB<Eigen::Matrix<float, -1, 3, 1, -1, 3>, 3>::init<Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&);
template double igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&) const;
template double igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::Matrix<double, 1, 2, 1, 1, 2> const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&) const;
#ifdef WIN32
template void igl::AABB<class Eigen::Matrix<double,-1,-1,0,-1,-1>,2>::squared_distance<class Eigen::Matrix<int,-1,-1,0,-1,-1>,class Eigen::Matrix<double,-1,-1,0,-1,-1>,class Eigen::Matrix<double,-1,1,0,-1,1>,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix<double,-1,3,0,-1,3> >(class Eigen::MatrixBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> > const &,class Eigen::MatrixBase<class Eigen::Matrix<int,-1,-1,0,-1,-1> > const &,class Eigen::MatrixBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,3,0,-1,3> > &)const;
template void igl::AABB<class Eigen::Matrix<double,-1,-1,0,-1,-1>,3>::squared_distance<class Eigen::Matrix<int,-1,-1,0,-1,-1>,class Eigen::Matrix<double,-1,-1,0,-1,-1>,class Eigen::Matrix<double,-1,1,0,-1,1>,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix<double,-1,3,0,-1,3> >(class Eigen::MatrixBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> > const &,class Eigen::MatrixBase<class Eigen::Matrix<int,-1,-1,0,-1,-1> > const &,class Eigen::MatrixBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,3,0,-1,3> > &)const;
+21
View File
@@ -0,0 +1,21 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Jérémie Dumas <jeremie.dumas@ens-lyon.org>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_FILEENCODING_H
#define IGL_FILEENCODING_H
namespace igl
{
enum class FileEncoding {
Binary,
Ascii
};
}
#endif
+7 -3
View File
@@ -17,9 +17,13 @@ namespace igl
struct Hit
{
int id; // primitive id
int gid; // geometry id
float u,v; // barycentric coordinates
float t; // distance = direction*t to intersection
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;
};
}
#endif
+497
View File
@@ -0,0 +1,497 @@
// based on MSH reader from PyMesh
// Copyright (c) 2015 Qingnan Zhou <qzhou@adobe.com>
// Copyright (C) 2020 Vladimir Fonov <vladimir.fonov@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "MshLoader.h"
#include <cassert>
#include <iostream>
#include <sstream>
#include <vector>
#include <string.h>
namespace igl {
// helper function
void inline _msh_eat_white_space(std::ifstream& fin) {
char next = fin.peek();
while (next == '\n' || next == ' ' || next == '\t' || next == '\r') {
fin.get();
next = fin.peek();
}
}
}
IGL_INLINE igl::MshLoader::MshLoader(const std::string &filename) {
std::ifstream fin(filename, std::ios::in | std::ios::binary);
if (!fin.is_open()) {
std::stringstream err_msg;
err_msg << "failed to open file \"" << filename << "\"";
throw std::ios_base::failure(err_msg.str());
}
// Parse header
std::string buf;
double version;
int type;
fin >> buf;
if (buf != "$MeshFormat") { throw std::runtime_error("Unexpected .msh format"); }
fin >> version >> type >> m_data_size;
m_binary = (type == 1);
if(version>2.2 || version<2.0)
{
// probably unsupported version
std::stringstream err_msg;
err_msg << "Error: Unsupported file version:" << version << std::endl;
throw std::runtime_error(err_msg.str());
}
// Some sanity check.
if (m_data_size != 8) {
std::stringstream err_msg;
err_msg << "Error: data size must be 8 bytes." << std::endl;
throw std::runtime_error(err_msg.str());
}
if (sizeof(int) != 4) {
std::stringstream err_msg;
err_msg << "Error: code must be compiled with int size 4 bytes." << std::endl;
throw std::runtime_error(err_msg.str());
}
// Read in extra info from binary header.
if (m_binary) {
int one;
igl::_msh_eat_white_space(fin);
fin.read(reinterpret_cast<char*>(&one), sizeof(int));
if (one != 1) {
std::stringstream err_msg;
err_msg << "Binary msh file " << filename
<< " is saved with different endianness than this machine."
<< std::endl;
throw std::runtime_error(err_msg.str());
}
}
fin >> buf;
if (buf != "$EndMeshFormat")
{
std::stringstream err_msg;
err_msg << "Unexpected contents in the file header." << std::endl;
throw std::runtime_error(err_msg.str());
}
while (!fin.eof()) {
buf.clear();
fin >> buf;
if (buf == "$Nodes") {
parse_nodes(fin);
fin >> buf;
if (buf != "$EndNodes") { throw std::runtime_error("Unexpected tag"); }
} else if (buf == "$Elements") {
parse_elements(fin);
fin >> buf;
if (buf != "$EndElements") { throw std::runtime_error("Unexpected tag"); }
} else if (buf == "$NodeData") {
parse_node_field(fin);
fin >> buf;
if (buf != "$EndNodeData") { throw std::runtime_error("Unexpected tag"); }
} else if (buf == "$ElementData") {
parse_element_field(fin);
fin >> buf;
if (buf != "$EndElementData") { throw std::runtime_error("Unexpected tag"); }
} else if (fin.eof()) {
break;
} else {
parse_unknown_field(fin, buf);
}
}
fin.close();
}
IGL_INLINE void igl::MshLoader::parse_nodes(std::ifstream& fin) {
size_t num_nodes;
fin >> num_nodes;
m_nodes.resize(num_nodes*3);
if (m_binary) {
size_t stride = (4+3*m_data_size);
size_t num_bytes = stride * num_nodes;
char* data = new char[num_bytes];
igl::_msh_eat_white_space(fin);
fin.read(data, num_bytes);
for (size_t i=0; i<num_nodes; i++) {
int node_idx;
memcpy(&node_idx, data+i*stride, sizeof(int));
node_idx-=1;
// directly move into vector storage
// this works only when m_data_size==sizeof(Float)==sizeof(double)
memcpy(&m_nodes[node_idx*3], data+i*stride + 4, m_data_size*3);
}
delete [] data;
} else {
int node_idx;
for (size_t i=0; i<num_nodes; i++) {
fin >> node_idx;
node_idx -= 1;
// here it's 3D node explicitly
fin >> m_nodes[node_idx*3]
>> m_nodes[node_idx*3+1]
>> m_nodes[node_idx*3+2];
}
}
}
IGL_INLINE void igl::MshLoader::parse_elements(std::ifstream& fin) {
m_elements_tags.resize(2); //hardcoded to have 2 tags
size_t num_elements;
fin >> num_elements;
size_t nodes_per_element;
if (m_binary) {
igl::_msh_eat_white_space(fin);
int elem_read = 0;
while (elem_read < num_elements) {
// Parse element header.
int elem_type, num_elems, num_tags;
fin.read((char*)&elem_type, sizeof(int));
fin.read((char*)&num_elems, sizeof(int));
fin.read((char*)&num_tags, sizeof(int));
nodes_per_element = num_nodes_per_elem_type(elem_type);
// store node info
for (size_t i=0; i<num_elems; i++) {
int elem_idx;
// all elements in the segment share the same elem_type and number of nodes per element
m_elements_types.push_back(elem_type);
m_elements_lengths.push_back(nodes_per_element);
fin.read((char*)&elem_idx, sizeof(int));
elem_idx -= 1;
m_elements_ids.push_back(elem_idx);
// read first two tags
for (size_t j=0; j<num_tags; j++) {
int tag;
fin.read((char*)&tag, sizeof(int));
if(j<2) m_elements_tags[j].push_back(tag);
}
for (size_t j=num_tags; j<2; j++)
m_elements_tags[j].push_back(-1); // fill up tags if less then 2
m_elements_nodes_idx.push_back(m_elements.size());
// Element values.
for (size_t j=0; j<nodes_per_element; j++) {
int idx;
fin.read((char*)&idx, sizeof(int));
m_elements.push_back(idx-1);
}
}
elem_read += num_elems;
}
} else {
for (size_t i=0; i<num_elements; i++) {
// Parse per element header
int elem_num, elem_type, num_tags;
fin >> elem_num >> elem_type >> num_tags;
// read tags.
for (size_t j=0; j<num_tags; j++) {
int tag;
fin >> tag;
if(j<2) m_elements_tags[j].push_back(tag);
}
for (size_t j=num_tags; j<2; j++)
m_elements_tags[j].push_back(-1); // fill up tags if less then 2
nodes_per_element = num_nodes_per_elem_type(elem_type);
m_elements_types.push_back(elem_type);
m_elements_lengths.push_back(nodes_per_element);
elem_num -= 1;
m_elements_ids.push_back(elem_num);
m_elements_nodes_idx.push_back(m_elements.size());
// Parse node idx.
for (size_t j=0; j<nodes_per_element; j++) {
int idx;
fin >> idx;
m_elements.push_back(idx-1); // msh index starts from 1.
}
}
}
// debug
assert(m_elements_types.size() == m_elements_ids.size());
assert(m_elements_tags[0].size() == m_elements_ids.size());
assert(m_elements_tags[1].size() == m_elements_ids.size());
assert(m_elements_lengths.size() == m_elements_ids.size());
}
IGL_INLINE void igl::MshLoader::parse_node_field( std::ifstream& fin ) {
size_t num_string_tags;
size_t num_real_tags;
size_t num_int_tags;
fin >> num_string_tags;
std::vector<std::string> str_tags(num_string_tags);
for (size_t i=0; i<num_string_tags; i++) {
igl::_msh_eat_white_space(fin);
if (fin.peek() == '\"') {
// Handle field name between quotes.
char buf[128];
fin.get(); // remove the quote at the beginning.
fin.getline(buf, 128, '\"');
str_tags[i] = std::string(buf);
} else {
fin >> str_tags[i];
}
}
fin >> num_real_tags;
std::vector<Float> real_tags(num_real_tags);
for (size_t i=0; i<num_real_tags; i++)
fin >> real_tags[i];
fin >> num_int_tags;
std::vector<int> int_tags(num_int_tags);
for (size_t i=0; i<num_int_tags; i++)
fin >> int_tags[i];
if (num_string_tags <= 0 || num_int_tags <= 2) {
throw std::runtime_error("Unexpected number of field tags");
}
std::string fieldname = str_tags[0];
int num_components = int_tags[1];
int num_entries = int_tags[2];
std::vector<Float> field( num_entries*num_components );
if (m_binary) {
size_t num_bytes = (num_components * m_data_size + 4) * num_entries;
char* data = new char[num_bytes];
igl::_msh_eat_white_space(fin);
fin.read(data, num_bytes);
for (size_t i=0; i<num_entries; i++) {
int node_idx;
memcpy(&node_idx,&data[i*(4+num_components*m_data_size)],4);
if(node_idx<1) throw std::runtime_error("Negative or zero index");
node_idx -= 1;
if(node_idx>=num_entries) throw std::runtime_error("Index too big");
size_t base_idx = i*(4+num_components*m_data_size) + 4;
// TODO: make this work when m_data_size != sizeof(double) ?
memcpy(&field[node_idx*num_components], &data[base_idx], num_components*m_data_size);
}
delete [] data;
} else {
int node_idx;
for (size_t i=0; i<num_entries; i++) {
fin >> node_idx;
node_idx -= 1;
for (size_t j=0; j<num_components; j++) {
fin >> field[node_idx*num_components+j];
}
}
}
m_node_fields_names.push_back(fieldname);
m_node_fields.push_back(field);
m_node_fields_components.push_back(num_components);
}
IGL_INLINE void igl::MshLoader::parse_element_field(std::ifstream& fin) {
size_t num_string_tags;
size_t num_real_tags;
size_t num_int_tags;
fin >> num_string_tags;
std::vector<std::string> str_tags(num_string_tags);
for (size_t i=0; i<num_string_tags; i++) {
igl::_msh_eat_white_space(fin);
if (fin.peek() == '\"') {
// Handle field name between quoates.
char buf[128];
fin.get(); // remove the quote at the beginning.
fin.getline(buf, 128, '\"');
str_tags[i] = buf;
} else {
fin >> str_tags[i];
}
}
fin >> num_real_tags;
std::vector<Float> real_tags(num_real_tags);
for (size_t i=0; i<num_real_tags; i++)
fin >> real_tags[i];
fin >> num_int_tags;
std::vector<int> int_tags(num_int_tags);
for (size_t i=0; i<num_int_tags; i++)
fin >> int_tags[i];
if (num_string_tags <= 0 || num_int_tags <= 2) {
throw std::runtime_error("Invalid file format");
}
std::string fieldname = str_tags[0];
int num_components = int_tags[1];
int num_entries = int_tags[2];
std::vector<Float> field(num_entries*num_components);
if (m_binary) {
size_t num_bytes = (num_components * m_data_size + 4) * num_entries;
char* data = new char[num_bytes];
igl::_msh_eat_white_space(fin);
fin.read(data, num_bytes);
for (int i=0; i<num_entries; i++) {
int elem_idx;
// works with sizeof(int)==4
memcpy(&elem_idx, &data[i*(4+num_components*m_data_size)],4);
elem_idx -= 1;
// directly copy data into vector storage space
memcpy(&field[elem_idx*num_components], &data[i*(4+num_components*m_data_size) + 4], m_data_size*num_components);
}
delete [] data;
} else {
int elem_idx;
for (size_t i=0; i<num_entries; i++) {
fin >> elem_idx;
elem_idx -= 1;
for (size_t j=0; j<num_components; j++) {
fin >> field[elem_idx*num_components+j];
}
}
}
m_element_fields_names.push_back(fieldname);
m_element_fields.push_back(field);
m_element_fields_components.push_back(num_components);
}
IGL_INLINE void igl::MshLoader::parse_unknown_field(std::ifstream& fin,
const std::string& fieldname) {
std::cerr << "Warning: \"" << fieldname << "\" not supported yet. Ignored." << std::endl;
std::string endmark = fieldname.substr(0,1) + "End"
+ fieldname.substr(1,fieldname.size()-1);
std::string buf("");
while (buf != endmark && !fin.eof()) {
fin >> buf;
}
}
IGL_INLINE int igl::MshLoader::num_nodes_per_elem_type(int elem_type) {
int nodes_per_element = 0;
switch (elem_type) {
case ELEMENT_LINE: // 2-node line
nodes_per_element = 2;
break;
case ELEMENT_TRI:
nodes_per_element = 3; // 3-node triangle
break;
case ELEMENT_QUAD:
nodes_per_element = 4; // 5-node quad
break;
case ELEMENT_TET:
nodes_per_element = 4; // 4-node tetrahedra
break;
case ELEMENT_HEX: // 8-node hexahedron
nodes_per_element = 8;
break;
case ELEMENT_PRISM: // 6-node prism
nodes_per_element = 6;
break;
case ELEMENT_LINE_2ND_ORDER:
nodes_per_element = 3;
break;
case ELEMENT_TRI_2ND_ORDER:
nodes_per_element = 6;
break;
case ELEMENT_QUAD_2ND_ORDER:
nodes_per_element = 9;
break;
case ELEMENT_TET_2ND_ORDER:
nodes_per_element = 10;
break;
case ELEMENT_HEX_2ND_ORDER:
nodes_per_element = 27;
break;
case ELEMENT_PRISM_2ND_ORDER:
nodes_per_element = 18;
break;
case ELEMENT_PYRAMID_2ND_ORDER:
nodes_per_element = 14;
break;
case ELEMENT_POINT: // 1-node point
nodes_per_element = 1;
break;
default:
std::stringstream err_msg;
err_msg << "Element type (" << elem_type << ") is not supported yet."
<< std::endl;
throw std::runtime_error(err_msg.str());
}
return nodes_per_element;
}
IGL_INLINE bool igl::MshLoader::is_element_map_identity() const
{
for(int i=0;i<m_elements_ids.size();i++) {
int id=m_elements_ids[i];
if (id!=i) return false;
}
return true;
}
IGL_INLINE void igl::MshLoader::index_structures(int tag_column)
{
//cleanup
m_structure_index.clear();
m_structures.clear();
m_structure_length.clear();
//index structure tags
for(auto i=0; i != m_elements_tags[tag_column].size(); ++i )
{
m_structure_index.insert(
std::pair<msh_struct,int>(
msh_struct( m_elements_tags[tag_column][i],
m_elements_types[i]), i)
);
}
// identify unique structures
std::vector<StructIndex::value_type> _unique_structs;
std::unique_copy(std::begin(m_structure_index),
std::end(m_structure_index),
std::back_inserter(_unique_structs),
[](const StructIndex::value_type &c1, const StructIndex::value_type &c2)
{ return c1.first == c2.first; });
std::for_each( _unique_structs.begin(), _unique_structs.end(),
[this](const StructIndex::value_type &n){ this->m_structures.push_back(n.first); });
for(auto t = m_structures.begin(); t != m_structures.end(); ++t)
{
// identify all elements corresponding to this tag
auto structure_range = m_structure_index.equal_range( *t );
int cnt=0;
for(auto i=structure_range.first; i!=structure_range.second; i++)
cnt++;
m_structure_length.insert( std::pair<msh_struct,int>( *t, cnt));
}
}
+190
View File
@@ -0,0 +1,190 @@
// based on MSH reader from PyMesh
// Copyright (c) 2015 Qingnan Zhou <qzhou@adobe.com>
// Copyright (C) 2020 Vladimir Fonov <vladimir.fonov@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_MSH_LOADER_H
#define IGL_MSH_LOADER_H
#include "igl_inline.h"
#include <fstream>
#include <map>
#include <string>
#include <vector>
#include <algorithm>
namespace igl {
// Class for loading information from .msh file
// depends only on c++stl library
class MshLoader {
public:
struct msh_struct {
int tag,el_type;
msh_struct(int _tag=0,int _type=0):
tag(_tag),el_type(_type){}
bool operator== (const msh_struct& a) const {
return this->tag==a.tag &&
this->el_type==a.el_type;
}
bool operator< (const msh_struct& a) const {
return (this->tag*100+this->el_type) <
(a.tag*100+a.el_type);
}
};
typedef double Float;
typedef std::vector<int> IndexVector;
typedef std::vector<int> IntVector;
typedef std::vector<Float> FloatVector;
typedef std::vector<FloatVector> FloatField;
typedef std::vector<IntVector> IntField;
typedef std::vector<std::string> FieldNames;
typedef std::multimap<msh_struct,int> StructIndex;
typedef std::vector<msh_struct> StructVector;
enum {ELEMENT_LINE=1, ELEMENT_TRI=2, ELEMENT_QUAD=3,
ELEMENT_TET=4, ELEMENT_HEX=5, ELEMENT_PRISM=6,
ELEMENT_PYRAMID=7,
// 2nd order elements
ELEMENT_LINE_2ND_ORDER=8, ELEMENT_TRI_2ND_ORDER=9,
ELEMENT_QUAD_2ND_ORDER=10,ELEMENT_TET_2ND_ORDER=11,
ELEMENT_HEX_2ND_ORDER=12, ELEMENT_PRISM_2ND_ORDER=13,
ELEMENT_PYRAMID_2ND_ORDER=14,
// other elements
ELEMENT_POINT=15 };
public:
MshLoader(const std::string &filename);
public:
// get nodes , x,y,z sequentially
const FloatVector& get_nodes() const { return m_nodes; }
// get elements , identifying nodes that create an element
// variable length per element
const IndexVector& get_elements() const { return m_elements; }
// get element types
const IntVector& get_elements_types() const { return m_elements_types; }
// get element lengths
const IntVector& get_elements_lengths() const { return m_elements_lengths; }
// get element tags ( physical (0) and elementary (1) )
const IntField& get_elements_tags() const { return m_elements_tags; }
// get element IDs
const IntVector& get_elements_ids() const { return m_elements_ids; }
// get reverse index from node to element
const IndexVector& get_elements_nodes_idx() const { return m_elements_nodes_idx; }
// get fields assigned per node, all fields and components sequentially
const FloatField& get_node_fields() const { return m_node_fields;}
// get node field names,
const FieldNames& get_node_fields_names() const { return m_node_fields_names;}
// get number of node field components
const IntVector& get_node_fields_components() const {return m_node_fields_components;}
int get_node_field_components(size_t c) const
{
return m_node_fields_components[c];
}
// get fields assigned per element, all fields and components sequentially
const FloatField& get_element_fields() const { return m_element_fields;}
// get element field names
const FieldNames& get_element_fields_names() const { return m_element_fields_names;}
// get number of element field components
const IntVector& get_element_fields_components() const {return m_element_fields_components;}
int get_element_field_components(size_t c) const {
return m_element_fields_components[c];
}
// check if field is present at node level
bool is_node_field(const std::string& fieldname) const {
return (std::find(std::begin(m_node_fields_names),
std::end(m_node_fields_names),
fieldname) != std::end(m_node_fields_names) );
}
// check if field is present at element level
bool is_element_field(const std::string& fieldname) const {
return (std::find(std::begin(m_element_fields_names),
std::end(m_element_fields_names),
fieldname) != std::end(m_node_fields_names) );
}
// check if all elements have ids assigned sequentially
bool is_element_map_identity() const ;
// create tag index
// tag_column: ( physical (0) or elementary (1) ) specifying which tag to use
void index_structures(int tag_column);
// get tag index, call index_structure_tags first
const StructIndex& get_structure_index() const
{
return m_structure_index;
}
// get size of a structure identified by tag and element type
const StructIndex& get_structure_length() const
{
return m_structure_length;
}
//! get list of structures
const StructVector& get_structures() const
{
return m_structures;
}
public:
// helper function, calculate number of nodes associated with an element
static int num_nodes_per_elem_type(int elem_type);
private:
void parse_nodes(std::ifstream& fin);
void parse_elements(std::ifstream& fin);
void parse_node_field(std::ifstream& fin);
void parse_element_field(std::ifstream& fin);
void parse_unknown_field(std::ifstream& fin,
const std::string& fieldname);
private:
bool m_binary;
size_t m_data_size;
FloatVector m_nodes; // len x 3 vector
IndexVector m_elements; // linear array for nodes corresponding to each element
IndexVector m_elements_nodes_idx; // element indexes
IntVector m_elements_ids; // element id's
IntVector m_elements_types; // Element types
IntVector m_elements_lengths; // Element lengths
IntField m_elements_tags; // Element tags, currently 2xtags per element
FloatField m_node_fields; // Float field defined at each node
IntVector m_node_fields_components; // Number of components for node field
FieldNames m_node_fields_names; // Node field name
FloatField m_element_fields; // Float field defined at each element
IntVector m_element_fields_components; // Number of components for element field
FieldNames m_element_fields_names; // Element field name
StructIndex m_structure_index; // index tag ids
StructVector m_structures; // unique structures
StructIndex m_structure_length; // length of structures with consistent element type
};
} //igl
#ifndef IGL_STATIC_LIBRARY
# include "MshLoader.cpp"
#endif
#endif //IGL_MSH_LOADER_H
+347
View File
@@ -0,0 +1,347 @@
// based on MSH writer from PyMesh
// Copyright (c) 2015 Qingnan Zhou <qzhou@adobe.com>
// Copyright (C) 2020 Vladimir Fonov <vladimir.fonov@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "MshSaver.h"
#include <cassert>
#include <iostream>
#include <sstream>
#include <exception>
IGL_INLINE igl::MshSaver::MshSaver(const std::string& filename, bool binary) :
m_binary(binary), m_num_nodes(0), m_num_elements(0) {
if (!m_binary) {
fout.open(filename.c_str(), std::fstream::out);
} else {
fout.open(filename.c_str(), std::fstream::binary);
}
if (!fout) {
std::stringstream err_msg;
err_msg << "Error opening " << filename << " to write msh file." << std::endl;
throw std::ios_base::failure(err_msg.str());
}
}
IGL_INLINE igl::MshSaver::~MshSaver() {
fout.close();
}
IGL_INLINE void igl::MshSaver::save_mesh(
const FloatVector& nodes,
const IndexVector& elements,
const IntVector& element_lengths,
const IntVector& element_types,
const IntVector& element_tags
) {
save_header();
save_nodes(nodes);
save_elements(elements, element_lengths, element_types, element_tags );
}
IGL_INLINE void igl::MshSaver::save_header() {
if (!m_binary) {
fout << "$MeshFormat" << std::endl;
fout << "2.2 0 " << sizeof(double) << std::endl;
fout << "$EndMeshFormat" << std::endl;
fout.precision(17);
} else {
fout << "$MeshFormat" << std::endl;
fout << "2.2 1 " << sizeof(double) << std::endl;
int one = 1;
fout.write((char*)&one, sizeof(int));
fout << "\n$EndMeshFormat" << std::endl;
}
fout.flush();
}
IGL_INLINE void igl::MshSaver::save_nodes(const FloatVector& nodes) {
// Save nodes.
// 3D hadrcoded
m_num_nodes = nodes.size() / 3;
fout << "$Nodes" << std::endl;
fout << m_num_nodes << std::endl;
if (!m_binary) {
for (size_t i=0; i<nodes.size(); i+=3) {
//const VectorF& v = nodes.segment(i,m_dim);
int node_idx = i/3 + 1;
fout << node_idx << " " << nodes[i] << " " << nodes[i+1] << " " << nodes[i+2] << std::endl;
}
} else {
for (size_t i=0; i<nodes.size(); i+=3) {
//const VectorF& v = nodes.segment(i,m_dim);
int node_idx = i/3 + 1;
fout.write((const char*)&node_idx, sizeof(int));
fout.write((const char*)&nodes[i], sizeof(Float)*3);
}
}
fout << "$EndNodes" << std::endl;
fout.flush();
}
IGL_INLINE void igl::MshSaver::save_elements(const IndexVector& elements,
const IntVector& element_lengths,
const IntVector& element_types,
const IntVector& element_tags)
{
m_num_elements = element_tags.size();
assert(element_lengths.size() == element_types.size() );
assert(element_lengths.size() == element_tags.size() );
// TODO: sum up all lengths
// Save elements.
// node inxes are 1-based
fout << "$Elements" << std::endl;
fout << m_num_elements << std::endl;
if (m_num_elements > 0) {
//int elem_type = el_type;
int num_elems = m_num_elements;
//int tags = 0;
if (!m_binary) {
size_t el_ptr=0;
for (size_t i=0;i<m_num_elements;++i) {
int elem_num = (int) i + 1;
///VectorI elem = elements.segment(i, nodes_per_element) + VectorI::Ones(nodes_per_element);
// hardcoded: duplicate tags (I don't know why)
fout << elem_num << " " << element_types[i] << " " << 2 << " "<< element_tags[i] << " "<< element_tags[i] << " ";
for (size_t j=0; j<element_lengths[i]; j++) {
fout << elements[el_ptr + j] + 1 << " ";
}
fout << std::endl;
el_ptr+=element_lengths[i];
}
} else {
size_t el_ptr=0,i=0;
while(i<m_num_elements) {
// write elements in consistent chunks
// TODO: refactor this code to be able to specify different elements
// more effeciently
int elem_type=-1;
int elem_len=-1;
size_t j=i;
for(;j<m_num_elements;++j)
{
if( elem_type==-1 )
{
elem_type=element_types[j];
elem_len=element_lengths[j];
} else if( elem_type!=element_types[j] ||
elem_len!=element_lengths[j]) {
break; // found the edge of the segment
}
}
//hardcoded: 2 tags
int num_elems=j-i, num_tags=2;
fout.write((const char*)& elem_type, sizeof(int));
fout.write((const char*)& num_elems, sizeof(int));
fout.write((const char*)& num_tags, sizeof(int));
for(int k=0;k<num_elems; ++k,++i){
int elem_num = (int )i + 1;
fout.write((const char*)&elem_num, sizeof(int));
// HACK: hardcoded 2 tags
fout.write((const char*)& element_tags[i], sizeof(int));
fout.write((const char*)& element_tags[i], sizeof(int));
for (size_t e=0; e<elem_len; e++) {
int _elem = static_cast<int>( elements[el_ptr + e] )+1;
fout.write((const char*)&_elem, sizeof(int));
}
el_ptr+=elem_len;
}
}
}
}
fout << "$EndElements" << std::endl;
fout.flush();
}
IGL_INLINE void igl::MshSaver::save_scalar_field(const std::string& fieldname, const FloatVector& field) {
assert(field.size() == m_num_nodes);
fout << "$NodeData" << std::endl;
fout << "1" << std::endl; // num string tags.
fout << "\"" << fieldname << "\"" << std::endl;
fout << "1" << std::endl; // num real tags.
fout << "0.0" << std::endl; // time value.
fout << "3" << std::endl; // num int tags.
fout << "0" << std::endl; // the time step
fout << "1" << std::endl; // 1-component scalar field.
fout << m_num_nodes << std::endl; // number of nodes
if (m_binary) {
for (size_t i=0; i<m_num_nodes; i++) {
int node_idx = i+1;
fout.write((char*)&node_idx, sizeof(int));
fout.write((char*)&field[i], sizeof(Float));
}
} else {
for (size_t i=0; i<m_num_nodes; i++) {
int node_idx = i+1;
fout << node_idx << " " << field[i] << std::endl;
}
}
fout << "$EndNodeData" << std::endl;
fout.flush();
}
IGL_INLINE void igl::MshSaver::save_vector_field(const std::string& fieldname, const FloatVector& field) {
assert(field.size() == 3 * m_num_nodes);
fout << "$NodeData" << std::endl;
fout << "1" << std::endl; // num string tags.
fout << "\"" << fieldname << "\"" << std::endl;
fout << "1" << std::endl; // num real tags.
fout << "0.0" << std::endl; // time value.
fout << "3" << std::endl; // num int tags.
fout << "0" << std::endl; // the time step
fout << "3" << std::endl; // 3-component vector field.
fout << m_num_nodes << std::endl; // number of nodes
const Float zero = 0.0;
if (m_binary) {
for (size_t i=0; i<m_num_nodes; i++) {
int node_idx = i+1;
fout.write((const char*)&node_idx, sizeof(int));
fout.write((const char*)&field[i*3], sizeof(Float)*3);
}
} else {
for (size_t i=0; i<m_num_nodes; i++) {
int node_idx = i+1;
fout << node_idx
<< " " << field[i*3]
<< " " << field[i*3+1]
<< " " << field[i*3+2]
<< std::endl;
}
}
fout << "$EndNodeData" << std::endl;
fout.flush();
}
IGL_INLINE void igl::MshSaver::save_elem_scalar_field(const std::string& fieldname, const FloatVector& field) {
assert(field.size() == m_num_elements);
fout << "$ElementData" << std::endl;
fout << 1 << std::endl; // num string tags.
fout << "\"" << fieldname << "\"" << std::endl;
fout << "1" << std::endl; // num real tags.
fout << "0.0" << std::endl; // time value.
fout << "3" << std::endl; // num int tags.
fout << "0" << std::endl; // the time step
fout << "1" << std::endl; // 1-component scalar field.
fout << m_num_elements << std::endl; // number of elements
if (m_binary) {
for (size_t i=0; i<m_num_elements; i++) {
int elem_idx = i+1;
fout.write((const char*)&elem_idx, sizeof(int));
fout.write((const char*)&field[i], sizeof(Float));
}
} else {
for (size_t i=0; i<m_num_elements; i++) {
int elem_idx = i+1;
fout << elem_idx << " " << field[i] << std::endl;
}
}
fout << "$EndElementData" << std::endl;
fout.flush();
}
IGL_INLINE void igl::MshSaver::save_elem_vector_field(const std::string& fieldname, const FloatVector& field) {
assert(field.size() == m_num_elements * 3);
fout << "$ElementData" << std::endl;
fout << 1 << std::endl; // num string tags.
fout << "\"" << fieldname << "\"" << std::endl;
fout << "1" << std::endl; // num real tags.
fout << "0.0" << std::endl; // time value.
fout << "3" << std::endl; // num int tags.
fout << "0" << std::endl; // the time step
fout << "3" << std::endl; // 3-component vector field.
fout << m_num_elements << std::endl; // number of elements
const Float zero = 0.0;
if (m_binary) {
for (size_t i=0; i<m_num_elements; ++i) {
int elem_idx = i+1;
fout.write((const char*)&elem_idx, sizeof(int));
fout.write((const char*)&field[i*3], sizeof(Float) * 3);
}
} else {
for (size_t i=0; i<m_num_elements; ++i) {
int elem_idx = i+1;
fout << elem_idx
<< " " << field[i*3]
<< " " << field[i*3+1]
<< " " << field[i*3+2]
<< std::endl;
}
}
fout << "$EndElementData" << std::endl;
fout.flush();
}
IGL_INLINE void igl::MshSaver::save_elem_tensor_field(const std::string& fieldname, const FloatVector& field) {
assert(field.size() == m_num_elements * 3 * (3 + 1) / 2);
fout << "$ElementData" << std::endl;
fout << 1 << std::endl; // num string tags.
fout << "\"" << fieldname << "\"" << std::endl;
fout << "1" << std::endl; // num real tags.
fout << "0.0" << std::endl; // time value.
fout << "3" << std::endl; // num int tags.
fout << "0" << std::endl; // the time step
fout << "9" << std::endl; // 9-component tensor field.
fout << m_num_elements << std::endl; // number of elements
const Float zero = 0.0;
if (m_binary) {
for (size_t i=0; i<m_num_elements; i++) {
int elem_idx = i+1;
fout.write((char*)&elem_idx, sizeof(int));
//const VectorF& val = field.segment(i*6, 6);
const Float* val = &field[i*6];
Float tensor[9] = {
val[0], val[5], val[4],
val[5], val[1], val[3],
val[4], val[3], val[2] };
fout.write((char*)tensor, sizeof(Float) * 9);
}
} else {
for (size_t i=0; i<m_num_elements; i++) {
int elem_idx = i+1;
const Float* val = &field[i*6];
fout << elem_idx
<< " " << val[0]
<< " " << val[5]
<< " " << val[4]
<< " " << val[5]
<< " " << val[1]
<< " " << val[3]
<< " " << val[4]
<< " " << val[3]
<< " " << val[2]
<< std::endl;
}
}
fout << "$EndElementData" << std::endl;
fout.flush();
}
+84
View File
@@ -0,0 +1,84 @@
// based on MSH writer from PyMesh
// Copyright (c) 2015 Qingnan Zhou <qzhou@adobe.com>
// Copyright (C) 2020 Vladimir Fonov <vladimir.fonov@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_MSH_SAVER_H
#define IGL_MSH_SAVER_H
#include "igl_inline.h"
#include <fstream>
#include <string>
#include <vector>
namespace igl {
// Class for dumping information to .msh file
// depends only on c++stl library
// current implementation works only with 3D information
class MshSaver {
public:
typedef double Float;
typedef std::vector<int> IndexVector;
typedef std::vector<int> IntVector;
typedef std::vector<Float> FloatVector;
typedef std::vector<FloatVector> FloatField;
typedef std::vector<IntVector> IntField;
typedef std::vector<std::string> FieldNames;
MshSaver(const std::string& filename, bool binary=true);
~MshSaver();
public:
// Only these element types are supported right now
enum {ELEMENT_LINE=1, ELEMENT_TRI=2, ELEMENT_QUAD=3,
ELEMENT_TET=4, ELEMENT_HEX=5, ELEMENT_PRISM=6 };
public:
// save mesh geometry
void save_mesh(
const FloatVector& nodes,
const IndexVector& elements,
const IntVector& element_lengths,
const IntVector& element_type,
const IntVector& element_tags );
// save additional fields associated with the mesh
// add node scalar field
void save_scalar_field(const std::string& fieldname, const FloatVector& field);
// add node vectot field
void save_vector_field(const std::string& fieldname, const FloatVector& field);
// add element scalar field
void save_elem_scalar_field(const std::string& fieldname, const FloatVector& field);
// add element vector field
void save_elem_vector_field(const std::string& fieldname, const FloatVector& field);
// add element tensor field
void save_elem_tensor_field(const std::string& fieldname, const FloatVector& field);
protected:
void save_header();
void save_nodes(const FloatVector& nodes);
void save_elements(const IndexVector& elements,
const IntVector& element_lengths,
const IntVector& element_type,
const IntVector& element_tags);
private:
bool m_binary;
size_t m_num_nodes;
size_t m_num_elements;
std::ofstream fout;
};
} //igl
#ifndef IGL_STATIC_LIBRARY
# include "MshSaver.cpp"
#endif
#endif //MSH_SAVER_H
+2 -2
View File
@@ -11,9 +11,9 @@ namespace igl
{
// Use standard mathematical constants' M_PI if available
#ifdef M_PI
const double PI = M_PI;
constexpr double PI = M_PI;
#else
const double PI = 3.1415926535897932384626433832795;
constexpr double PI = 3.1415926535897932384626433832795;
#endif
}
#endif
+12
View File
@@ -374,4 +374,16 @@ 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
+50
View File
@@ -65,8 +65,58 @@ IGL_INLINE void igl::adjacency_matrix(
}
}
template <typename DerivedI, typename DerivedC, typename T>
IGL_INLINE void igl::adjacency_matrix(
const Eigen::MatrixBase<DerivedI> & I,
const Eigen::MatrixBase<DerivedC> & C,
Eigen::SparseMatrix<T>& A)
{
using namespace std;
using namespace Eigen;
typedef Triplet<T> IJV;
vector<IJV > ijv;
ijv.reserve(C(C.size()-1)*2);
typedef typename DerivedI::Scalar Index;
const Index n = I.maxCoeff()+1;
{
// loop over polygons
for(Index p = 0;p<C.size()-1;p++)
{
// number of edges
const Index np = C(p+1)-C(p);
// loop over edges
for(Index c = 0;c<np;c++)
{
const Index i = I(C(p)+c);
const Index j = I(C(p)+((c+1)%np));
ijv.emplace_back(i,j,1);
ijv.emplace_back(j,i,1);
}
}
}
A.resize(n,n);
A.reserve(6*n);
A.setFromTriplets(ijv.begin(),ijv.end());
// Force all non-zeros to be one
// Iterate over outside
for(int k=0; k<A.outerSize(); ++k)
{
// Iterate over inside
for(typename Eigen::SparseMatrix<T>::InnerIterator it (A,k); it; ++it)
{
assert(it.value() != 0);
A.coeffRef(it.row(),it.col()) = 1;
}
}
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<int, 0, int>& );
// generated by autoexplicit.sh
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, -1, 0, -1, -1>, bool>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<bool, 0, int>&);
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
+16 -1
View File
@@ -21,7 +21,7 @@ namespace igl
// Inputs:
// F #F by dim list of mesh simplices
// Outputs:
// A max(F) by max(F) adjacency matrix, each row i corresponding to V(i,:)
// A max(F)+1 by max(F)+1 adjacency matrix, each row i corresponding to V(i,:)
//
// Example:
// // Mesh in (V,F)
@@ -42,6 +42,21 @@ namespace igl
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,:)
//
template <typename DerivedI, typename DerivedC, typename T>
IGL_INLINE void adjacency_matrix(
const Eigen::MatrixBase<DerivedI> & I,
const Eigen::MatrixBase<DerivedC> & C,
Eigen::SparseMatrix<T>& A);
}
#ifndef IGL_STATIC_LIBRARY
-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/.
#include "all_edges.h"
#include "oriented_facets.h"
template <typename DerivedF, typename DerivedE>
IGL_INLINE void igl::all_edges(
const Eigen::MatrixBase<DerivedF> & F,
Eigen::PlainObjectBase<DerivedE> & E)
{
return oriented_facets(F,E);
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template void igl::all_edges<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
template void igl::all_edges<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
template void igl::all_edges<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
template void igl::all_edges<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
template void igl::all_edges<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
#endif
-39
View File
@@ -1,39 +0,0 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ALL_EDGES_H
#define IGL_ALL_EDGES_H
#include "igl_inline.h"
#include "deprecated.h"
#include <Eigen/Dense>
namespace igl
{
// Deprecated: call oriented_facets instead.
//
// ALL_EDGES Determines all "directed edges" of a given set of simplices. For
// a manifold mesh, this computes all of the half-edges
//
// Inputs:
// F #F by simplex_size list of "faces"
// Outputs:
// E #E by simplex_size-1 list of edges
//
// Note: this is not the same as igl::edges because this includes every
// directed edge including repeats (meaning interior edges on a surface will
// show up once for each direction and non-manifold edges may appear more than
// once for each direction).
template <typename DerivedF, typename DerivedE>
IGL_DEPRECATED IGL_INLINE void all_edges(
const Eigen::MatrixBase<DerivedF> & F,
Eigen::PlainObjectBase<DerivedE> & E);
}
#ifndef IGL_STATIC_LIBRARY
# include "all_edges.cpp"
#endif
#endif
+2
View File
@@ -128,6 +128,8 @@ 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> >&);
+3 -3
View File
@@ -27,7 +27,7 @@
#include "get_seconds_hires.h"
//#include "MKLEigenInterface.h"
#include "min_quad_dense.h"
#include "kkt_inverse.h"
#include "get_seconds.h"
#include "columnize.h"
@@ -543,7 +543,7 @@ IGL_INLINE bool igl::arap_dof_recomputation(
#endif
// Compute dense solve matrix (alternative of matrix factorization)
//printf("min_quad_dense_precompute()\n");
//printf("kkt_inverse()\n");
MatrixXd Qfull(*Q);
MatrixXd A_eqfull(A_eq);
MatrixXd M_Solve;
@@ -552,7 +552,7 @@ IGL_INLINE bool igl::arap_dof_recomputation(
bool use_lu = data.effective_dim != 2;
//use_lu = false;
//printf("use_lu: %s\n",(use_lu?"TRUE":"FALSE"));
min_quad_dense_precompute(Qfull, A_eqfull, use_lu,M_Solve);
kkt_inverse(Qfull, A_eqfull, use_lu,M_Solve);
double timer0_end = get_seconds_hires();
verbose("Bob timing: %.20f\n", (timer0_end - timer0_start)*1000.0);
@@ -0,0 +1,68 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "average_from_edges_onto_vertices.h"
template<typename DerivedF,typename DerivedE,typename DerivedoE,
typename DeriveduE,typename DeriveduV>
IGL_INLINE void
igl::average_from_edges_onto_vertices(
const Eigen::MatrixBase<DerivedF> &F,
const Eigen::MatrixBase<DerivedE> &E,
const Eigen::MatrixBase<DerivedoE> &oE,
const Eigen::MatrixBase<DeriveduE> &uE,
Eigen::PlainObjectBase<DeriveduV> &uV)
{
using Scalar = typename DeriveduE::Scalar;
using VecX = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
using Int = typename DerivedF::Scalar;
assert(E.rows()==F.rows() && "E does not match dimensions of F.");
assert(oE.rows()==F.rows() && "oE does not match dimensions of F.");
assert(E.cols()==3 && F.cols()==3 && oE.cols()==3 &&
"This method is for triangle meshes.");
const Int n = F.maxCoeff()+1;
VecX edgesPerVertex(n);
edgesPerVertex.setZero();
uV.resize(n,1);
uV.setZero();
for(Eigen::Index i=0; i<F.rows(); ++i) {
for(int j=0; j<3; ++j) {
if(oE(i,j)<0) {
continue;
}
const Int e = E(i,j);
const Int vi=F(i,(j+1)%3), vj=F(i,(j+2)%3);
//Count vertex valence
++edgesPerVertex(vi);
++edgesPerVertex(vj);
//Average uE value onto vertices
uV(vi) += uE(e);
uV(vj) += uE(e);
}
}
//Divide by valence
for(Int i=0; i<n; ++i) {
const Scalar valence = edgesPerVertex(i);
if(valence>0) {
uV(i) /= valence;
}
}
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template void igl::average_from_edges_onto_vertices<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::PartialReduxExpr<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::internal::member_norm<double>, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::PartialReduxExpr<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::internal::member_norm<double>, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template void igl::average_from_edges_onto_vertices<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template void igl::average_from_edges_onto_vertices<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
#endif
@@ -0,0 +1,39 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_AVERAGE_FROM_EDGES_ONTO_VERTICES_H
#define IGL_AVERAGE_FROM_EDGES_ONTO_VERTICES_H
#include "igl_inline.h"
#include <Eigen/Dense>
namespace igl
{
// Move a scalar field defined on edges to vertices by averaging
//
// Input:
// F: triangle mesh connectivity
// E, oE: mapping from halfedges to edges and orientation as generated by
// orient_halfedges
// uE: scalar field defined on edges, one per edge
//
// Output:
// uV: scalar field defined on vertices
template<typename DerivedF,typename DerivedE,typename DerivedoE,
typename DeriveduE,typename DeriveduV>
IGL_INLINE void average_from_edges_onto_vertices(
const Eigen::MatrixBase<DerivedF> &F,
const Eigen::MatrixBase<DerivedE> &E,
const Eigen::MatrixBase<DerivedoE> &oE,
const Eigen::MatrixBase<DeriveduE> &uE,
Eigen::PlainObjectBase<DeriveduV> &uV);
}
#ifndef IGL_STATIC_LIBRARY
# include "average_from_edges_onto_vertices.cpp"
#endif
#endif
+2
View File
@@ -22,4 +22,6 @@ IGL_INLINE void igl::average_onto_faces(
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::average_onto_faces<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
#endif
+1 -6
View File
@@ -34,18 +34,13 @@ IGL_INLINE void igl::barycenter(
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
template void igl::barycenter<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 4, 0, -1, 4> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> >&);
template void igl::barycenter<Eigen::Matrix<double, -1, 4, 0, -1, 4>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 4, 0, -1, 4> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> >&);
+42
View File
@@ -0,0 +1,42 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "barycentric_interpolation.h"
#include "parallel_for.h"
template <
typename DerivedD,
typename DerivedF,
typename DerivedB,
typename DerivedI,
typename DerivedX>
IGL_INLINE void igl::barycentric_interpolation(
const Eigen::MatrixBase<DerivedD> & D,
const Eigen::MatrixBase<DerivedF> & F,
const Eigen::MatrixBase<DerivedB> & B,
const Eigen::MatrixBase<DerivedI> & I,
Eigen::PlainObjectBase<DerivedX> & X)
{
assert(B.rows() == I.size());
assert(F.cols() == B.cols());
X.setZero(B.rows(),D.cols());
// should use parallel_for
//for(int i = 0;i<X.rows();i++)
parallel_for(X.rows(),[&X,&B,&D,&F,&I](const int i)
{
for(int j = 0;j<F.cols();j++)
{
X.row(i) += B(i,j) * D.row(F(I(i),j));
}
},1000);
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::barycentric_interpolation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
#endif
+42
View File
@@ -0,0 +1,42 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_BARYCENTRIC_INTERPOLATION_H
#define IGL_BARYCENTRIC_INTERPOLATION_H
#include "igl_inline.h"
#include <Eigen/Core>
namespace igl
{
// Interpolate data on a triangle mesh using barycentric coordinates
//
// Inputs:
// D #D by dim list of per-vertex data
// F #F by 3 list of triangle indices
// B #X by 3 list of barycentric corodinates
// I #X list of triangle indices
// Outputs:
// X #X by dim list of interpolated data
template <
typename DerivedD,
typename DerivedF,
typename DerivedB,
typename DerivedI,
typename DerivedX>
IGL_INLINE void barycentric_interpolation(
const Eigen::MatrixBase<DerivedD> & D,
const Eigen::MatrixBase<DerivedF> & F,
const Eigen::MatrixBase<DerivedB> & B,
const Eigen::MatrixBase<DerivedI> & I,
Eigen::PlainObjectBase<DerivedX> & X);
}
#ifndef IGL_STATIC_LIBRARY
# include "barycentric_interpolation.cpp"
#endif
#endif
-44
View File
@@ -1,44 +0,0 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "barycentric_to_global.h"
// For error printing
#include <cstdio>
#include <vector>
namespace igl
{
template <typename Scalar, typename Index>
IGL_INLINE Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> barycentric_to_global(
const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & V,
const Eigen::Matrix<Index,Eigen::Dynamic,Eigen::Dynamic> & F,
const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & bc)
{
Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> R;
R.resize(bc.rows(),3);
for (unsigned i=0; i<R.rows(); ++i)
{
unsigned id = round(bc(i,0));
double u = bc(i,1);
double v = bc(i,2);
if (id != -1)
R.row(i) = V.row(F(id,0)) +
((V.row(F(id,1)) - V.row(F(id,0))) * u +
(V.row(F(id,2)) - V.row(F(id,0))) * v );
else
R.row(i) << 0,0,0;
}
return R;
}
}
#ifdef IGL_STATIC_LIBRARY
template Eigen::Matrix<double, -1, -1, 0, -1, -1> igl::barycentric_to_global<double, int>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&);
#endif
-42
View File
@@ -1,42 +0,0 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_BARYCENTRIC2GLOBAL_H
#define IGL_BARYCENTRIC2GLOBAL_H
#include <igl/igl_inline.h>
#include <Eigen/Dense>
#include <Eigen/Sparse>
namespace igl
{
// Converts barycentric coordinates in the embree form to 3D coordinates
// Embree stores barycentric coordinates as triples: fid, bc1, bc2
// fid is the id of a face, bc1 is the displacement of the point wrt the
// first vertex v0 and the edge v1-v0. Similarly, bc2 is the displacement
// wrt v2-v0.
//
// Input:
// V: #Vx3 Vertices of the mesh
// F: #Fxe Faces of the mesh
// bc: #Xx3 Barycentric coordinates, one row per point
//
// Output:
// #X: #Xx3 3D coordinates of all points in bc
template <typename Scalar, typename Index>
IGL_INLINE Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>
barycentric_to_global(
const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & V,
const Eigen::Matrix<Index,Eigen::Dynamic,Eigen::Dynamic> & F,
const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & bc);
}
#ifndef IGL_STATIC_LIBRARY
# include "barycentric_to_global.cpp"
#endif
#endif
+71
View File
@@ -0,0 +1,71 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "blkdiag.h"
template <typename Scalar>
IGL_INLINE void igl::blkdiag(
const std::vector<Eigen::SparseMatrix<Scalar>> & L,
Eigen::SparseMatrix<Scalar> & Y)
{
int nr = 0;
int nc = 0;
int nnz = 0;
for(const auto & A : L)
{
nr += A.rows();
nc += A.cols();
}
Y.resize(nr,nc);
{
int i = 0;
int j = 0;
for(const auto & A : L)
{
for(int k = 0;k<A.outerSize();++k)
{
for(typename Eigen::SparseMatrix<Scalar>::InnerIterator it(A,k);it;++it)
{
Y.insert(i+it.row(),j+k) = it.value();
}
}
i += A.rows();
j += A.cols();
}
}
}
template <typename DerivedY>
IGL_INLINE void igl::blkdiag(
const std::vector<DerivedY> & L,
Eigen::PlainObjectBase<DerivedY> & Y)
{
int nr = 0;
int nc = 0;
for(const auto & A : L)
{
nr += A.rows();
nc += A.cols();
}
Y.setZero(nr,nc);
{
int i = 0;
int j = 0;
for(const auto & A : L)
{
Y.block(i,j,A.rows(),A.cols()) = A;
i += A.rows();
j += A.cols();
}
}
}
#ifdef IGL_STATIC_LIBRARY
// explicit template instantiations
template void igl::blkdiag<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::vector<Eigen::Matrix<double, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<double, -1, -1, 0, -1, -1> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template void igl::blkdiag<double>(std::vector<Eigen::SparseMatrix<double, 0, int>, std::allocator<Eigen::SparseMatrix<double, 0, int> > > const&, Eigen::SparseMatrix<double, 0, int>&);
#endif
+40
View File
@@ -0,0 +1,40 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_BLKDIAG_H
#define IGL_BLKDIAG_H
#include "igl_inline.h"
#include <Eigen/Core>
#include <Eigen/Sparse>
#include <vector>
namespace igl
{
// Given a list of matrices place them along the diagonal as blocks of the
// output matrix. Like matlab's blkdiag.
//
// Inputs:
// L list of matrices {A,B, ...}
// Outputs:
// Y A.rows()+B.rows()+... by A.cols()+B.cols()+... block diagonal
//
// See also: cat, repdiag
template <typename Scalar>
IGL_INLINE void blkdiag(
const std::vector<Eigen::SparseMatrix<Scalar>> & L,
Eigen::SparseMatrix<Scalar> & Y);
template <typename DerivedY>
IGL_INLINE void blkdiag(
const std::vector<DerivedY> & L,
Eigen::PlainObjectBase<DerivedY> & Y);
}
#ifndef IGL_STATIC_LIBRARY
# include "blkdiag.cpp"
#endif
#endif
+372
View File
@@ -0,0 +1,372 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "blue_noise.h"
#include "doublearea.h"
#include "random_points_on_mesh.h"
#include "slice.h"
#include "sortrows.h"
#include "PI.h"
#include "get_seconds.h"
#include <unordered_map>
#include <algorithm>
#include <vector>
namespace igl
{
// It is very important that we use 64bit keys to avoid out of bounds (easy to
// get to happen with dense samplings (e.g., r = 0.0005*bbd)
typedef int64_t BlueNoiseKeyType;
}
// Helper functions
namespace igl
{
// Should probably find and replace with less generic name
//
// Map 3D subscripts (x,y,z) to unique index (return value)
//
// Inputs:
// w side length of w×w×w integer cube lattice
// x subscript along x direction
// y subscript along y direction
// z subscript along z direction
// Returns index value
//
inline BlueNoiseKeyType blue_noise_key(
const BlueNoiseKeyType w, // pass by copy --> int64_t so that multiplication is OK
const BlueNoiseKeyType x, // pass by copy --> int64_t so that multiplication is OK
const BlueNoiseKeyType y, // pass by copy --> int64_t so that multiplication is OK
const BlueNoiseKeyType z) // pass by copy --> int64_t so that multiplication is OK
{
return x+w*(y+w*z);
}
// Determine if a query candidate at position X.row(i) is too close to already
// selected sites (stored in S).
//
// Inputs:
// X #X by 3 list of raw candidate positions
// Xs #Xs by 3 list of corresponding integer cell subscripts
// i index of candidate in question
// S map from cell index to index into X of selected candidate (or -1 if
// cell is currently empty)
// rr Poisson disk radius squared
// w side length of w×w×w integer cube lattice (into which Xs subscripts)
template <
typename DerivedX,
typename DerivedXs>
inline bool blue_noise_far_enough(
const Eigen::MatrixBase<DerivedX> & X,
const Eigen::MatrixBase<DerivedXs> & Xs,
const std::unordered_map<BlueNoiseKeyType,int> & S,
const double & rr,
const int & w,
const int i)
{
const int xi = Xs(i,0);
const int yi = Xs(i,1);
const int zi = Xs(i,2);
BlueNoiseKeyType k = blue_noise_key(w,xi,yi,zi);
int g = 2; // ceil(r/s)
for(int x = std::max(xi-g,0);x<=std::min(xi+g,w-1);x++)
for(int y = std::max(yi-g,0);y<=std::min(yi+g,w-1);y++)
for(int z = std::max(zi-g,0);z<=std::min(zi+g,w-1);z++)
{
if(x!=xi || y!=yi || z!=zi)
{
const BlueNoiseKeyType nk = blue_noise_key(w,x,y,z);
// have already selected from this cell
const auto Siter = S.find(nk);
if(Siter !=S.end() && Siter->second >= 0)
{
const int ni = Siter->second;
// too close
if( (X.row(i)-X.row(ni)).squaredNorm() < rr)
{
return false;
}
}
}
}
return true;
}
// Try to activate a candidate in a given cell
//
// Inputs:
// X #X by 3 list of raw candidate positions
// Xs #Xs by 3 list of corresponding integer cell subscripts
// rr Poisson disk radius squared
// w side length of w×w×w integer cube lattice (into which Xs subscripts)
// nk index of cell in which we'd like to activate a candidate
// M map from cell index to list of candidates
// S map from cell index to index into X of selected candidate (or -1 if
// cell is currently empty)
// active list of indices into X of active candidates
// Outputs:
// M visited candidates deemed too close to already selected points are
// removed
// S updated to reflect activated point (if successful)
// active updated to reflect activated point (if successful)
// Returns true iff activation was successful
template <
typename DerivedX,
typename DerivedXs>
inline bool activate(
const Eigen::MatrixBase<DerivedX> & X,
const Eigen::MatrixBase<DerivedXs> & Xs,
const double & rr,
const int & i,
const int & w,
const BlueNoiseKeyType & nk,
std::unordered_map<BlueNoiseKeyType,std::vector<int> > & M,
std::unordered_map<BlueNoiseKeyType,int> & S,
std::vector<int> & active)
{
assert(M.count(nk));
auto & Mvec = M.find(nk)->second;
auto miter = Mvec.begin();
while(miter != Mvec.end())
{
const int mi = *miter;
// mi is our candidate sample. Is it far enough from all existing
// samples?
if(i>=0 && (X.row(i)-X.row(mi)).squaredNorm() > 4.*rr)
{
// too far skip (reject)
miter++;
} else if(blue_noise_far_enough(X,Xs,S,rr,w,mi))
{
active.push_back(mi);
S.find(nk)->second = mi;
//printf(" found %d\n",mi);
return true;
}else
{
// remove forever (instead of incrementing we swap and eat from the
// back)
//std::swap(*miter,Mvec.back());
*miter = Mvec.back();
bool was_last = (std::next(miter) == Mvec.end());
Mvec.pop_back();
if (was_last) {
// popping from the vector can invalidate the iterator, if it was
// pointing to the last element that was popped. Alternatively,
// one could use indices directly...
miter = Mvec.end();
}
}
}
return false;
}
template <
typename DerivedX,
typename DerivedXs>
inline bool step(
const Eigen::MatrixBase<DerivedX> & X,
const Eigen::MatrixBase<DerivedXs> & Xs,
const double & rr,
const int & w,
std::unordered_map<BlueNoiseKeyType,std::vector<int> > & M,
std::unordered_map<BlueNoiseKeyType,int> & S,
std::vector<int> & active,
std::vector<int> & collected
)
{
//considered.clear();
if(active.size() == 0) return false;
// random entry
const int e = rand() % active.size();
const int i = active[e];
//printf("%d\n",i);
const int xi = Xs(i,0);
const int yi = Xs(i,1);
const int zi = Xs(i,2);
//printf("%d %d %d - %g %g %g\n",xi,yi,zi,X(i,0),X(i,1),X(i,2));
// cell indices of neighbors
int g = 4;
std::vector<BlueNoiseKeyType> N;N.reserve((1+g*1)^3-1);
for(int x = std::max(xi-g,0);x<=std::min(xi+g,w-1);x++)
for(int y = std::max(yi-g,0);y<=std::min(yi+g,w-1);y++)
for(int z = std::max(zi-g,0);z<=std::min(zi+g,w-1);z++)
{
if(x!=xi || y!=yi || z!=zi)
{
//printf(" %d %d %d\n",x,y,z);
const BlueNoiseKeyType nk = blue_noise_key(w,x,y,z);
// haven't yet selected from this cell?
const auto Siter = S.find(nk);
if(Siter !=S.end() && Siter->second < 0)
{
assert(M.find(nk) != M.end());
N.emplace_back(nk);
}
}
}
//printf(" --------\n");
// randomize order: this might be a little paranoid...
std::random_shuffle(std::begin(N), std::end(N));
bool found = false;
for(const BlueNoiseKeyType & nk : N)
{
assert(M.find(nk) != M.end());
if(activate(X,Xs,rr,i,w,nk,M,S,active))
{
found = true;
break;
}
}
if(!found)
{
// remove i from active list
// https://stackoverflow.com/a/60765833/148668
collected.push_back(i);
//printf(" before: "); for(const int j : active) { printf("%d ",j); } printf("\n");
std::swap(active[e], active.back());
//printf(" after : "); for(const int j : active) { printf("%d ",j); } printf("\n");
active.pop_back();
//printf(" removed %d\n",i);
}
//printf(" active: "); for(const int j : active) { printf("%d ",j); } printf("\n");
return true;
}
}
template <
typename DerivedV,
typename DerivedF,
typename DerivedB,
typename DerivedFI,
typename DerivedP>
IGL_INLINE void igl::blue_noise(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F,
const typename DerivedV::Scalar r,
Eigen::PlainObjectBase<DerivedB> & B,
Eigen::PlainObjectBase<DerivedFI> & FI,
Eigen::PlainObjectBase<DerivedP> & P)
{
typedef typename DerivedV::Scalar Scalar;
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,1> VectorXS;
// float+RowMajor is faster...
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,3,Eigen::RowMajor> MatrixX3S;
assert(V.cols() == 3 && "Only 3D embeddings allowed");
// minimum radius
const Scalar min_r = r;
// cell size based on 3D distance
// It works reasonably well (but is probably biased to use s=2*r/√3 here and
// g=1 in the outer loop below.
//
// One thing to try would be to store a list in S (rather than a single point)
// or equivalently a mask over M and just use M as a generic spatial hash
// (with arbitrary size) and then tune its size (being careful to make g a
// function of r and s; and removing the `if S=-1 checks`)
const Scalar s = r/sqrt(3.0);
const double area =
[&](){Eigen::VectorXd A;igl::doublearea(V,F,A);return A.array().sum()/2;}();
// Circle packing in the plane has igl::PI*sqrt(3)/6 efficiency
const double expected_number_of_points =
area * (igl::PI * sqrt(3.0) / 6.0) / (igl::PI * min_r * min_r / 4.0);
// Make a uniform random sampling with 30*expected_number_of_points.
const int nx = 30.0*expected_number_of_points;
MatrixX3S X,XB;
Eigen::VectorXi XFI;
igl::random_points_on_mesh(nx,V,F,XB,XFI,X);
// Rescale so that s = 1
Eigen::Matrix<int,Eigen::Dynamic,3,Eigen::RowMajor> Xs =
((X.rowwise()-X.colwise().minCoeff())/s).template cast<int>();
const int w = Xs.maxCoeff()+1;
{
Eigen::VectorXi I;
igl::sortrows(decltype(Xs)(Xs),true,Xs,I);
igl::slice(decltype(X)(X),I,1,X);
// These two could be spun off in their own thread.
igl::slice(decltype(XB)(XB),I,1,XB);
igl::slice(decltype(XFI)(XFI),I,1,XFI);
}
// Initialization
std::unordered_map<BlueNoiseKeyType,std::vector<int> > M;
std::unordered_map<BlueNoiseKeyType, int > S;
// attempted to seed
std::unordered_map<BlueNoiseKeyType, int > A;
// Q: Too many?
// A: Seems to help though.
M.reserve(Xs.rows());
S.reserve(Xs.rows());
for(int i = 0;i<Xs.rows();i++)
{
BlueNoiseKeyType k = blue_noise_key(w,Xs(i,0),Xs(i,1),Xs(i,2));
const auto Miter = M.find(k);
if(Miter == M.end())
{
M.insert({k,{i}});
}else
{
Miter->second.push_back(i);
}
S.emplace(k,-1);
A.emplace(k,false);
}
std::vector<int> active;
// precompute r²
// Q: is this necessary?
const double rr = r*r;
std::vector<int> collected;
collected.reserve(2.0*expected_number_of_points);
auto Mouter = M.begin();
// Just take the first point as the initial seed
const auto initialize = [&]()->bool
{
while(true)
{
if(Mouter == M.end())
{
return false;
}
const BlueNoiseKeyType k = Mouter->first;
// Haven't placed in this cell yet
if(S[k]<0)
{
if(activate(X,Xs,rr,-1,w,k,M,S,active)) return true;
}
Mouter++;
}
assert(false && "should not be reachable.");
};
// important if mesh contains many connected components
while(initialize())
{
while(active.size()>0)
{
step(X,Xs,rr,w,M,S,active,collected);
}
}
{
const int n = collected.size();
P.resize(n,3);
B.resize(n,3);
FI.resize(n);
for(int i = 0;i<n;i++)
{
const int c = collected[i];
P.row(i) = X.row(c).template cast<typename DerivedP::Scalar>();
B.row(i) = XB.row(c).template cast<typename DerivedB::Scalar>();
FI(i) = XFI(c);
}
}
}
#ifdef IGL_STATIC_LIBRARY
template void igl::blue_noise<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<float, -1, 3, 1, -1, 3>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template void igl::blue_noise<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
#endif
+49
View File
@@ -0,0 +1,49 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_BLUE_NOISE_H
#define IGL_BLUE_NOISE_H
#include "igl_inline.h"
#include <Eigen/Core>
namespace igl
{
// "Fast Poisson Disk Sampling in Arbitrary Dimensions" [Bridson 2007]
//
// For very dense samplings this is faster than (up to 2x) cyCodeBase's
// implementation of "Sample Elimination for Generating Poisson Disk Sample
// Sets" [Yuksel 2015]. YMMV
//
// Inputs:
// V #V by dim list of mesh vertex positions
// F #F by 3 list of mesh triangle indices into rows of V
// r Poisson disk radius (evaluated according to Euclidean distance on V)
// Outputs:
// B #P by 3 list of barycentric coordinates, ith row are coordinates of
// ith sampled point in face FI(i)
// FI #P list of indices into F
// P #P by dim list of sample positions.
// See also: random_points_on_mesh
template <
typename DerivedV,
typename DerivedF,
typename DerivedB,
typename DerivedFI,
typename DerivedP>
IGL_INLINE void blue_noise(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F,
const typename DerivedV::Scalar r,
Eigen::PlainObjectBase<DerivedB> & B,
Eigen::PlainObjectBase<DerivedFI> & FI,
Eigen::PlainObjectBase<DerivedP> & P);
}
#ifndef IGL_STATIC_LIBRARY
# include "blue_noise.cpp"
#endif
#endif
+74
View File
@@ -67,3 +67,77 @@ IGL_INLINE void igl::circulation(
std::vector<int> N = circulation(e,ccw,EMAP,EF,EI);
igl::list_to_matrix(N,vN);
}
IGL_INLINE void igl::circulation(
const int e,
const bool ccw,
const Eigen::MatrixXi & F,
const Eigen::VectorXi & EMAP,
const Eigen::MatrixXi & EF,
const Eigen::MatrixXi & EI,
/*std::vector<int> & Ne,*/
std::vector<int> & Nv,
std::vector<int> & Nf)
{
//
// for e --> (bf) and ccw=true
//
// c---d
// / \ / \
// a---b-e-f
// \ / \ /
// g---h
//
// // (might start with {bhf} depending on edge)
// Ne = […] -> [fd db dc cb ca ab ag gb gh hb hf fb]
// {upto cylic order}
// Nf = […] -> [{bfd}, {bdc}, {bca}, {bag}, {bgh}, {bhf}]
// Nv = [d c a g h f]
//
// prepare output
//Ne.clear();Ne.reserve(2*10);
Nv.clear();Nv.reserve(10);
Nf.clear();Nf.reserve(10);
const int m = EMAP.size()/3;
assert(m*3 == EMAP.size());
const auto & step = [&](
const int e,
const int ff,
int & ne,
//int & re,
int & rv,
int & nf)
{
assert((EF(e,1) == ff || EF(e,0) == ff) && "e should touch ff");
//const int fside = EF(e,1)==ff?1:0;
const int nside = EF(e,0)==ff?1:0;
const int nv = EI(e,nside);
// get next face
nf = EF(e,nside);
// get next edge
const int dir = ccw?-1:1;
rv = F(nf,nv);
ne = EMAP(nf+m*((nv+dir+3)%3));
//re = EMAP(nf+m*((nv+2*dir+3)%3));
};
// Always start with first face (ccw in step will be sure to turn right
// direction)
const int f0 = EF(e,0);
int fi = f0;
int ei = e;
while(true)
{
int re,rv;
step(ei,fi,ei/*,re*/,rv,fi);
Nf.push_back(fi);
//Ne.push_back(re);
//Ne.push_back(ei);
Nv.push_back(rv);
// back to start?
if(fi == f0)
{
assert(ei == e);
break;
}
}
}
+14
View File
@@ -43,6 +43,20 @@ namespace igl
const Eigen::MatrixXi & EF,
const Eigen::MatrixXi & EI,
Eigen::VectorXi & vN);
// Outputs:
//// Ne 2*#Nf list of indices into E of "next" rim-spoke-rim-spoke-...
// Nv #Nv list of "next" vertex indices
// Nf #Nf list of face indices
IGL_INLINE void circulation(
const int e,
const bool ccw,
const Eigen::MatrixXi & F,
const Eigen::VectorXi & EMAP,
const Eigen::MatrixXi & EF,
const Eigen::MatrixXi & EI,
/*std::vector<int> & Ne,*/
std::vector<int> & Nv,
std::vector<int> & Nf);
}
#ifndef IGL_STATIC_LIBRARY
+159 -180
View File
@@ -8,6 +8,7 @@
#include "collapse_edge.h"
#include "circulation.h"
#include "edge_collapse_is_valid.h"
#include "decimate_trivial_callbacks.h"
#include <vector>
IGL_INLINE bool igl::collapse_edge(
@@ -19,6 +20,32 @@ IGL_INLINE bool igl::collapse_edge(
Eigen::VectorXi & EMAP,
Eigen::MatrixXi & EF,
Eigen::MatrixXi & EI,
int & e1,
int & e2,
int & f1,
int & f2)
{
std::vector<int> /*Nse,*/Nsf,Nsv;
circulation(e, true,F,EMAP,EF,EI,/*Nse,*/Nsv,Nsf);
std::vector<int> /*Nde,*/Ndf,Ndv;
circulation(e, false,F,EMAP,EF,EI,/*Nde,*/Ndv,Ndf);
return collapse_edge(
e,p,Nsv,Nsf,Ndv,Ndf,V,F,E,EMAP,EF,EI,e1,e2,f1,f2);
}
IGL_INLINE bool igl::collapse_edge(
const int e,
const Eigen::RowVectorXd & p,
/*const*/ std::vector<int> & Nsv,
const std::vector<int> & Nsf,
/*const*/ std::vector<int> & Ndv,
const std::vector<int> & Ndf,
Eigen::MatrixXd & V,
Eigen::MatrixXi & F,
Eigen::MatrixXi & E,
Eigen::VectorXi & EMAP,
Eigen::MatrixXi & EF,
Eigen::MatrixXi & EI,
int & a_e1,
int & a_e2,
int & a_f1,
@@ -34,17 +61,19 @@ IGL_INLINE bool igl::collapse_edge(
const int s = eflip?E(e,1):E(e,0);
const int d = eflip?E(e,0):E(e,1);
if(!edge_collapse_is_valid(e,F,E,EMAP,EF,EI))
if(!edge_collapse_is_valid(Nsv,Ndv))
{
return false;
}
// OVERLOAD: caller may have just computed this
//
// Important to grab neighbors of d before monkeying with edges
const std::vector<int> nV2Fd = circulation(e,!eflip,EMAP,EF,EI);
const std::vector<int> & nV2Fd = (!eflip ? Nsf : Ndf);
// The following implementation strongly relies on s<d
assert(s<d && "s should be less than d");
// move source and destination to midpoint
// move source and destination to placement
V.row(s) = p;
V.row(d) = p;
@@ -112,31 +141,40 @@ IGL_INLINE bool igl::collapse_edge(
// make sense.
//
// Could actually skip first and last, since those are always the two
// collpased faces.
for(auto f : nV2Fd)
// collpased faces. Nah, this is handled by (F(f,v) == d)
//
// Don't attempt to use Nde,Nse here because EMAP has changed
{
for(int v = 0;v<3;v++)
int p1 = -1;
for(auto f : nV2Fd)
{
if(F(f,v) == d)
for(int v = 0;v<3;v++)
{
const int flip1 = (EF(EMAP(f+m*((v+1)%3)),0)==f)?1:0;
const int flip2 = (EF(EMAP(f+m*((v+2)%3)),0)==f)?0:1;
assert(
E(EMAP(f+m*((v+1)%3)),flip1) == d ||
E(EMAP(f+m*((v+1)%3)),flip1) == s);
E(EMAP(f+m*((v+1)%3)),flip1) = s;
assert(
E(EMAP(f+m*((v+2)%3)),flip2) == d ||
E(EMAP(f+m*((v+2)%3)),flip2) == s);
E(EMAP(f+m*((v+2)%3)),flip2) = s;
F(f,v) = s;
break;
if(F(f,v) == d)
{
const int e1 = EMAP(f+m*((v+1)%3));
const int flip1 = (EF(e1,0)==f)?1:0;
assert( E(e1,flip1) == d || E(e1,flip1) == s);
E(e1,flip1) = s;
const int e2 = EMAP(f+m*((v+2)%3));
// Skip if we just handled this edge (claim: this will be all except
// for the first non-trivial face)
if(e2 != p1)
{
const int flip2 = (EF(e2,0)==f)?0:1;
assert( E(e2,flip2) == d || E(e2,flip2) == s);
E(e2,flip2) = s;
}
F(f,v) = s;
p1 = e1;
break;
}
}
}
}
// Finally, "remove" this edge and its information
kill_edge(e);
return true;
}
@@ -155,168 +193,61 @@ IGL_INLINE bool igl::collapse_edge(
}
IGL_INLINE bool igl::collapse_edge(
const std::function<void(
const int,
const Eigen::MatrixXd &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
const Eigen::VectorXi &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
double &,
Eigen::RowVectorXd &)> & cost_and_placement,
const decimate_cost_and_placement_callback & cost_and_placement,
Eigen::MatrixXd & V,
Eigen::MatrixXi & F,
Eigen::MatrixXi & E,
Eigen::VectorXi & EMAP,
Eigen::MatrixXi & EF,
Eigen::MatrixXi & EI,
std::set<std::pair<double,int> > & Q,
std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
igl::min_heap< std::tuple<double,int,int> > & Q,
Eigen::VectorXi & EQ,
Eigen::MatrixXd & C)
{
int e,e1,e2,f1,f2;
const auto always_try = [](
const Eigen::MatrixXd & ,/*V*/
const Eigen::MatrixXi & ,/*F*/
const Eigen::MatrixXi & ,/*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & ,/*EF*/
const Eigen::MatrixXi & ,/*EI*/
const std::set<std::pair<double,int> > & ,/*Q*/
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
const Eigen::MatrixXd & ,/*C*/
const int /*e*/
) -> bool { return true;};
const auto never_care = [](
const Eigen::MatrixXd & , /*V*/
const Eigen::MatrixXi & , /*F*/
const Eigen::MatrixXi & , /*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & , /*EF*/
const Eigen::MatrixXi & , /*EI*/
const std::set<std::pair<double,int> > & , /*Q*/
const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
const Eigen::MatrixXd & , /*C*/
const int , /*e*/
const int , /*e1*/
const int , /*e2*/
const int , /*f1*/
const int , /*f2*/
const bool /*collapsed*/
)-> void { };
decimate_pre_collapse_callback always_try;
decimate_post_collapse_callback never_care;
decimate_trivial_callbacks(always_try,never_care);
return
collapse_edge(
cost_and_placement,always_try,never_care,
V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2);
V,F,E,EMAP,EF,EI,Q,EQ,C,e,e1,e2,f1,f2);
}
IGL_INLINE bool igl::collapse_edge(
const std::function<void(
const int,
const Eigen::MatrixXd &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
const Eigen::VectorXi &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
double &,
Eigen::RowVectorXd &)> & cost_and_placement,
const std::function<bool(
const Eigen::MatrixXd & ,/*V*/
const Eigen::MatrixXi & ,/*F*/
const Eigen::MatrixXi & ,/*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & ,/*EF*/
const Eigen::MatrixXi & ,/*EI*/
const std::set<std::pair<double,int> > & ,/*Q*/
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
const Eigen::MatrixXd & ,/*C*/
const int /*e*/
)> & pre_collapse,
const std::function<void(
const Eigen::MatrixXd & , /*V*/
const Eigen::MatrixXi & , /*F*/
const Eigen::MatrixXi & , /*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & , /*EF*/
const Eigen::MatrixXi & , /*EI*/
const std::set<std::pair<double,int> > & , /*Q*/
const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
const Eigen::MatrixXd & , /*C*/
const int , /*e*/
const int , /*e1*/
const int , /*e2*/
const int , /*f1*/
const int , /*f2*/
const bool /*collapsed*/
)> & post_collapse,
const decimate_cost_and_placement_callback & cost_and_placement,
const decimate_pre_collapse_callback & pre_collapse,
const decimate_post_collapse_callback & post_collapse,
Eigen::MatrixXd & V,
Eigen::MatrixXi & F,
Eigen::MatrixXi & E,
Eigen::VectorXi & EMAP,
Eigen::MatrixXi & EF,
Eigen::MatrixXi & EI,
std::set<std::pair<double,int> > & Q,
std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
igl::min_heap< std::tuple<double,int,int> > & Q,
Eigen::VectorXi & EQ,
Eigen::MatrixXd & C)
{
int e,e1,e2,f1,f2;
return
collapse_edge(
cost_and_placement,pre_collapse,post_collapse,
V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2);
V,F,E,EMAP,EF,EI,Q,EQ,C,e,e1,e2,f1,f2);
}
IGL_INLINE bool igl::collapse_edge(
const std::function<void(
const int,
const Eigen::MatrixXd &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
const Eigen::VectorXi &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
double &,
Eigen::RowVectorXd &)> & cost_and_placement,
const std::function<bool(
const Eigen::MatrixXd & ,/*V*/
const Eigen::MatrixXi & ,/*F*/
const Eigen::MatrixXi & ,/*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & ,/*EF*/
const Eigen::MatrixXi & ,/*EI*/
const std::set<std::pair<double,int> > & ,/*Q*/
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
const Eigen::MatrixXd & ,/*C*/
const int /*e*/
)> & pre_collapse,
const std::function<void(
const Eigen::MatrixXd & , /*V*/
const Eigen::MatrixXi & , /*F*/
const Eigen::MatrixXi & , /*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & , /*EF*/
const Eigen::MatrixXi & , /*EI*/
const std::set<std::pair<double,int> > & , /*Q*/
const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
const Eigen::MatrixXd & , /*C*/
const int , /*e*/
const int , /*e1*/
const int , /*e2*/
const int , /*f1*/
const int , /*f2*/
const bool /*collapsed*/
)> & post_collapse,
const decimate_cost_and_placement_callback & cost_and_placement,
const decimate_pre_collapse_callback & pre_collapse,
const decimate_post_collapse_callback & post_collapse,
Eigen::MatrixXd & V,
Eigen::MatrixXi & F,
Eigen::MatrixXi & E,
Eigen::VectorXi & EMAP,
Eigen::MatrixXi & EF,
Eigen::MatrixXi & EI,
std::set<std::pair<double,int> > & Q,
std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
igl::min_heap< std::tuple<double,int,int> > & Q,
Eigen::VectorXi & EQ,
Eigen::MatrixXd & C,
int & e,
int & e1,
@@ -325,43 +256,82 @@ IGL_INLINE bool igl::collapse_edge(
int & f2)
{
using namespace Eigen;
if(Q.empty())
using namespace igl;
std::tuple<double,int,int> p;
while(true)
{
// no edges to collapse
return false;
// Check if Q is empty
if(Q.empty())
{
// no edges to collapse
e = -1;
return false;
}
// pop from Q
p = Q.top();
if(std::get<0>(p) == std::numeric_limits<double>::infinity())
{
e = -1;
// min cost edge is infinite cost
return false;
}
Q.pop();
e = std::get<1>(p);
// Check if matches timestamp
if(std::get<2>(p) == EQ(e))
{
break;
}
// must be stale or dead.
assert(std::get<2>(p) < EQ(e) || EQ(e) == -1);
// try again.
}
std::pair<double,int> p = *(Q.begin());
if(p.first == std::numeric_limits<double>::infinity())
{
// min cost edge is infinite cost
return false;
}
Q.erase(Q.begin());
e = p.second;
Qit[e] = Q.end();
std::vector<int> N = circulation(e, true,EMAP,EF,EI);
std::vector<int> Nd = circulation(e,false,EMAP,EF,EI);
N.insert(N.begin(),Nd.begin(),Nd.end());
// Why is this computed up here?
// If we just need original face neighbors of edge, could we gather that more
// directly than gathering face neighbors of each vertex?
std::vector<int> /*Nse,*/Nsf,Nsv;
circulation(e, true,F,EMAP,EF,EI,/*Nse,*/Nsv,Nsf);
std::vector<int> /*Nde,*/Ndf,Ndv;
circulation(e, false,F,EMAP,EF,EI,/*Nde,*/Ndv,Ndf);
bool collapsed = true;
if(pre_collapse(V,F,E,EMAP,EF,EI,Q,Qit,C,e))
if(pre_collapse(V,F,E,EMAP,EF,EI,Q,EQ,C,e))
{
collapsed = collapse_edge(e,C.row(e),V,F,E,EMAP,EF,EI,e1,e2,f1,f2);
collapsed = collapse_edge(
e,C.row(e),
Nsv,Nsf,Ndv,Ndf,
V,F,E,EMAP,EF,EI,e1,e2,f1,f2);
}else
{
// Aborted by pre collapse callback
collapsed = false;
}
post_collapse(V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2,collapsed);
post_collapse(V,F,E,EMAP,EF,EI,Q,EQ,C,e,e1,e2,f1,f2,collapsed);
if(collapsed)
{
// Erase the two, other collapsed edges
Q.erase(Qit[e1]);
Qit[e1] = Q.end();
Q.erase(Qit[e2]);
Qit[e2] = Q.end();
// Erase the two, other collapsed edges by marking their timestamps as -1
EQ(e1) = -1;
EQ(e2) = -1;
// TODO: visits edges multiple times, ~150% more updates than should
//
// update local neighbors
// loop over original face neighbors
for(auto n : N)
//
// Can't use previous computed Nse and Nde because those refer to EMAP
// before it was changed...
std::vector<int> Nf;
Nf.reserve( Nsf.size() + Ndf.size() ); // preallocate memory
Nf.insert( Nf.end(), Nsf.begin(), Nsf.end() );
Nf.insert( Nf.end(), Ndf.begin(), Ndf.end() );
// https://stackoverflow.com/a/1041939/148668
std::sort( Nf.begin(), Nf.end() );
Nf.erase( std::unique( Nf.begin(), Nf.end() ), Nf.end() );
// Collect all edges that must be updated
std::vector<int> Ne;
Ne.reserve(3*Nf.size());
for(auto & n : Nf)
{
if(F(n,0) != IGL_COLLAPSE_EDGE_NULL ||
F(n,1) != IGL_COLLAPSE_EDGE_NULL ||
@@ -371,24 +341,33 @@ IGL_INLINE bool igl::collapse_edge(
{
// get edge id
const int ei = EMAP(v*F.rows()+n);
// erase old entry
Q.erase(Qit[ei]);
// compute cost and potential placement
double cost;
RowVectorXd place;
cost_and_placement(ei,V,F,E,EMAP,EF,EI,cost,place);
// Replace in queue
Qit[ei] = Q.insert(std::pair<double,int>(cost,ei)).first;
C.row(ei) = place;
Ne.push_back(ei);
}
}
}
// Only process edge once
std::sort( Ne.begin(), Ne.end() );
Ne.erase( std::unique( Ne.begin(), Ne.end() ), Ne.end() );
for(auto & ei : Ne)
{
// compute cost and potential placement
double cost;
RowVectorXd place;
cost_and_placement(ei,V,F,E,EMAP,EF,EI,cost,place);
// Increment timestamp
EQ(ei)++;
// Replace in queue
Q.emplace(cost,ei,EQ(ei));
C.row(ei) = place;
}
}else
{
// reinsert with infinite weight (the provided cost function must **not**
// have given this un-collapsable edge inf cost already)
p.first = std::numeric_limits<double>::infinity();
Qit[e] = Q.insert(p).first;
// Increment timestamp
EQ(e)++;
// Replace in queue
Q.emplace(std::numeric_limits<double>::infinity(),e,EQ(e));
}
return collapsed;
}
+42 -97
View File
@@ -8,6 +8,8 @@
#ifndef IGL_COLLAPSE_EDGE_H
#define IGL_COLLAPSE_EDGE_H
#include "igl_inline.h"
#include "min_heap.h"
#include "decimate_callback_types.h"
#include <Eigen/Core>
#include <vector>
#include <set>
@@ -55,6 +57,24 @@ namespace igl
int & e2,
int & f1,
int & f2);
// Inputs:
IGL_INLINE bool collapse_edge(
const int e,
const Eigen::RowVectorXd & p,
/*const*/ std::vector<int> & Nsv,
const std::vector<int> & Nsf,
/*const*/ std::vector<int> & Ndv,
const std::vector<int> & Ndf,
Eigen::MatrixXd & V,
Eigen::MatrixXi & F,
Eigen::MatrixXi & E,
Eigen::VectorXi & EMAP,
Eigen::MatrixXi & EF,
Eigen::MatrixXi & EI,
int & e1,
int & e2,
int & f1,
int & f2);
IGL_INLINE bool collapse_edge(
const int e,
const Eigen::RowVectorXd & p,
@@ -73,28 +93,19 @@ namespace igl
// **If the edges is collapsed** then this function will be called on all
// edges of all faces previously incident on the endpoints of the
// collapsed edge.
// Q queue containing pairs of costs and edge indices
// Qit list of iterators so that Qit[e] --> iterator of edge e in Q
// Q queue containing pairs of costs and edge indices and insertion "time"
// EQ #E list of "time" of last time pushed into Q
// C #E by dim list of stored placements
IGL_INLINE bool collapse_edge(
const std::function<void(
const int,
const Eigen::MatrixXd &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
const Eigen::VectorXi &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
double &,
Eigen::RowVectorXd &)> & cost_and_placement,
const decimate_cost_and_placement_callback & cost_and_placement,
Eigen::MatrixXd & V,
Eigen::MatrixXi & F,
Eigen::MatrixXi & E,
Eigen::VectorXi & EMAP,
Eigen::MatrixXi & EF,
Eigen::MatrixXi & EI,
std::set<std::pair<double,int> > & Q,
std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
igl::min_heap< std::tuple<double,int,int> > & Q,
Eigen::VectorXi & EQ,
Eigen::MatrixXd & C);
// Inputs:
// pre_collapse callback called with index of edge whose collapse is about
@@ -105,103 +116,37 @@ namespace igl
// post_collapse callback called with index of edge whose collapse was
// just attempted and a flag revealing whether this was successful.
IGL_INLINE bool collapse_edge(
const std::function<void(
const int,
const Eigen::MatrixXd &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
const Eigen::VectorXi &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
double &,
Eigen::RowVectorXd &)> & cost_and_placement,
const std::function<bool(
const Eigen::MatrixXd & ,/*V*/
const Eigen::MatrixXi & ,/*F*/
const Eigen::MatrixXi & ,/*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & ,/*EF*/
const Eigen::MatrixXi & ,/*EI*/
const std::set<std::pair<double,int> > & ,/*Q*/
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
const Eigen::MatrixXd & ,/*C*/
const int /*e*/
)> & pre_collapse,
const std::function<void(
const Eigen::MatrixXd & , /*V*/
const Eigen::MatrixXi & , /*F*/
const Eigen::MatrixXi & , /*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & , /*EF*/
const Eigen::MatrixXi & , /*EI*/
const std::set<std::pair<double,int> > & , /*Q*/
const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
const Eigen::MatrixXd & , /*C*/
const int , /*e*/
const int , /*e1*/
const int , /*e2*/
const int , /*f1*/
const int , /*f2*/
const bool /*collapsed*/
)> & post_collapse,
const decimate_cost_and_placement_callback & cost_and_placement,
const decimate_pre_collapse_callback & pre_collapse,
const decimate_post_collapse_callback & post_collapse,
Eigen::MatrixXd & V,
Eigen::MatrixXi & F,
Eigen::MatrixXi & E,
Eigen::VectorXi & EMAP,
Eigen::MatrixXi & EF,
Eigen::MatrixXi & EI,
std::set<std::pair<double,int> > & Q,
std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
igl::min_heap< std::tuple<double,int,int> > & Q,
Eigen::VectorXi & EQ,
Eigen::MatrixXd & C);
// Outputs:
// e index into E of attempted collapsed edge. Set to -1 if Q is empty or
// contains only infinite cost edges.
// e1 index into E of edge collpased on left.
// e2 index into E of edge collpased on right.
// f1 index into F of face collpased on left.
// f2 index into F of face collpased on right.
IGL_INLINE bool collapse_edge(
const std::function<void(
const int,
const Eigen::MatrixXd &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
const Eigen::VectorXi &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
double &,
Eigen::RowVectorXd &)> & cost_and_placement,
const std::function<bool(
const Eigen::MatrixXd & ,/*V*/
const Eigen::MatrixXi & ,/*F*/
const Eigen::MatrixXi & ,/*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & ,/*EF*/
const Eigen::MatrixXi & ,/*EI*/
const std::set<std::pair<double,int> > & ,/*Q*/
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
const Eigen::MatrixXd & ,/*C*/
const int /*e*/
)> & pre_collapse,
const std::function<void(
const Eigen::MatrixXd & , /*V*/
const Eigen::MatrixXi & , /*F*/
const Eigen::MatrixXi & , /*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & , /*EF*/
const Eigen::MatrixXi & , /*EI*/
const std::set<std::pair<double,int> > & , /*Q*/
const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
const Eigen::MatrixXd & , /*C*/
const int , /*e*/
const int , /*e1*/
const int , /*e2*/
const int , /*f1*/
const int , /*f2*/
const bool /*collapsed*/
)> & post_collapse,
const decimate_cost_and_placement_callback & cost_and_placement,
const decimate_pre_collapse_callback & pre_collapse,
const decimate_post_collapse_callback & post_collapse,
Eigen::MatrixXd & V,
Eigen::MatrixXi & F,
Eigen::MatrixXi & E,
Eigen::VectorXi & EMAP,
Eigen::MatrixXi & EF,
Eigen::MatrixXi & EI,
std::set<std::pair<double,int> > & Q,
std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
igl::min_heap< std::tuple<double,int,int> > & Q,
Eigen::VectorXi & EQ,
Eigen::MatrixXd & C,
int & e,
int & e1,
+2
View File
@@ -49,6 +49,8 @@ igl::copyleft::cgal::assign(
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
// generated by autoexplicit.sh
template void igl::copyleft::cgal::assign<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
// generated by autoexplicit.sh
template void igl::copyleft::cgal::assign<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&);
@@ -96,6 +96,8 @@ IGL_INLINE void igl::copyleft::cgal::convex_hull(
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::copyleft::cgal::convex_hull<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
// generated by autoexplicit.sh
template void igl::copyleft::cgal::convex_hull<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
template void igl::copyleft::cgal::convex_hull<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
template void igl::copyleft::cgal::convex_hull<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
@@ -48,6 +48,8 @@ IGL_INLINE void igl::copyleft::cgal::mesh_to_cgal_triangle_list(
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Simple_cartesian<double> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Simple_cartesian<double> >, std::allocator<CGAL::Triangle_3<CGAL::Simple_cartesian<double> > > >&);
// generated by autoexplicit.sh
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
// generated by autoexplicit.sh
template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
@@ -382,6 +382,8 @@ IGL_INLINE void igl::copyleft::cgal::minkowski_sum(
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::copyleft::cgal::minkowski_sum<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, 3, 1, double, 3, 1, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
// generated by autoexplicit.sh
template void igl::copyleft::cgal::minkowski_sum<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, CGAL::Lazy_exact_nt<CGAL::Gmpq>, 3, 1, CGAL::Lazy_exact_nt<CGAL::Gmpq>, 3, 1, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 3, 1, 1, 3> const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 3, 1, 1, 3> const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
// generated by autoexplicit.sh
template void igl::copyleft::cgal::minkowski_sum<
@@ -133,7 +133,10 @@ IGL_INLINE void igl::copyleft::cgal::point_mesh_squared_distance(
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::copyleft::cgal::point_mesh_squared_distance<CGAL::Simple_cartesian<double>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 1, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, CGAL::AABB_tree<CGAL::AABB_traits<CGAL::Simple_cartesian<double>, CGAL::AABB_triangle_primitive<CGAL::Simple_cartesian<double>, std::vector<CGAL::Triangle_3<CGAL::Simple_cartesian<double> >, std::allocator<CGAL::Triangle_3<CGAL::Simple_cartesian<double> > > >::iterator, CGAL::Boolean_tag<false> >, CGAL::Default> > const&, std::vector<CGAL::Triangle_3<CGAL::Simple_cartesian<double> >, std::allocator<CGAL::Triangle_3<CGAL::Simple_cartesian<double> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&);
template void igl::copyleft::cgal::point_mesh_squared_distance<CGAL::Epeck, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template void igl::copyleft::cgal::point_mesh_squared_distance<CGAL::Epeck, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template void igl::copyleft::cgal::point_mesh_squared_distance_precompute<CGAL::Simple_cartesian<double>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, CGAL::AABB_tree<CGAL::AABB_traits<CGAL::Simple_cartesian<double>, CGAL::AABB_triangle_primitive<CGAL::Simple_cartesian<double>, std::vector<CGAL::Triangle_3<CGAL::Simple_cartesian<double> >, std::allocator<CGAL::Triangle_3<CGAL::Simple_cartesian<double> > > >::iterator, CGAL::Boolean_tag<false> >, CGAL::Default> >&, std::vector<CGAL::Triangle_3<CGAL::Simple_cartesian<double> >, std::allocator<CGAL::Triangle_3<CGAL::Simple_cartesian<double> > > >&);
template void igl::copyleft::cgal::point_mesh_squared_distance_precompute<CGAL::Simple_cartesian<double>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, CGAL::AABB_tree<CGAL::AABB_traits<CGAL::Simple_cartesian<double>, CGAL::AABB_triangle_primitive<CGAL::Simple_cartesian<double>, std::vector<CGAL::Triangle_3<CGAL::Simple_cartesian<double> >, std::allocator<CGAL::Triangle_3<CGAL::Simple_cartesian<double> > > >::iterator, CGAL::Boolean_tag<false> >, CGAL::Default> >&, std::vector<CGAL::Triangle_3<CGAL::Simple_cartesian<double> >, std::allocator<CGAL::Triangle_3<CGAL::Simple_cartesian<double> > > >&);
#endif
@@ -61,9 +61,11 @@ IGL_INLINE void igl::copyleft::cgal::polyhedron_to_mesh(
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polyhedron_items_with_id_3.h>
template void igl::copyleft::cgal::polyhedron_to_mesh<CGAL::Polyhedron_3<CGAL::Epick, CGAL::Polyhedron_items_3, CGAL::HalfedgeDS_default, std::allocator<int> >, Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(CGAL::Polyhedron_3<CGAL::Epick, CGAL::Polyhedron_items_3, CGAL::HalfedgeDS_default, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
template void igl::copyleft::cgal::polyhedron_to_mesh<CGAL::Polyhedron_3<CGAL::Epick, CGAL::Polyhedron_items_3, CGAL::HalfedgeDS_default, std::allocator<int> >, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(CGAL::Polyhedron_3<CGAL::Epick, CGAL::Polyhedron_items_3, CGAL::HalfedgeDS_default, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
template void igl::copyleft::cgal::polyhedron_to_mesh<CGAL::Polyhedron_3<CGAL::Simple_cartesian<double>,CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator<int> >, Eigen::Matrix<double, -1, -1, 0,-1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(CGAL::Polyhedron_3<CGAL::Simple_cartesian<double>,CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator<int> > const&,Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0,-1, -1> >&);
#endif
+1
View File
@@ -39,6 +39,7 @@ namespace igl
// vertices #V by 3 list of mesh vertex positions
// faces #F by 3 list of mesh triangle indices
//
// See also: igl::marching_cubes
template <typename DerivedValues, typename DerivedPoints, typename DerivedVertices, typename DerivedFaces>
IGL_INLINE void marching_cubes(
const Eigen::MatrixBase<DerivedValues> &values,
-64
View File
@@ -1,64 +0,0 @@
#include "offset_surface.h"
#include "marching_cubes.h"
#include "../voxel_grid.h"
#include "../signed_distance.h"
#include "../flood_fill.h"
#include <cassert>
template <
typename DerivedV,
typename DerivedF,
typename isolevelType,
typename DerivedSV,
typename DerivedSF,
typename DerivedGV,
typename Derivedside,
typename DerivedS>
void igl::copyleft::offset_surface(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F,
const isolevelType isolevel,
const typename Derivedside::Scalar s,
const SignedDistanceType & signed_distance_type,
Eigen::PlainObjectBase<DerivedSV> & SV,
Eigen::PlainObjectBase<DerivedSF> & SF,
Eigen::PlainObjectBase<DerivedGV> & GV,
Eigen::PlainObjectBase<Derivedside> & side,
Eigen::PlainObjectBase<DerivedS> & S)
{
typedef typename DerivedV::Scalar Scalar;
typedef typename DerivedF::Scalar Index;
{
Eigen::AlignedBox<Scalar,3> box;
typedef Eigen::Matrix<Scalar,1,3> RowVector3S;
assert(V.cols() == 3 && "V must contain positions in 3D");
RowVector3S min_ext = V.colwise().minCoeff().array() - isolevel;
RowVector3S max_ext = V.colwise().maxCoeff().array() + isolevel;
box.extend(min_ext.transpose());
box.extend(max_ext.transpose());
igl::voxel_grid(box,s,1,GV,side);
}
const Scalar h =
(GV.col(0).maxCoeff()-GV.col(0).minCoeff())/((Scalar)(side(0)-1));
const Scalar lower_bound = isolevel-sqrt(3.0)*h;
const Scalar upper_bound = isolevel+sqrt(3.0)*h;
{
Eigen::Matrix<Index,Eigen::Dynamic,1> I;
Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,3> C,N;
igl::signed_distance(
GV,V,F,signed_distance_type,lower_bound,upper_bound,S,I,C,N);
}
igl::flood_fill(side,S);
DerivedS SS = S.array()-isolevel;
igl::copyleft::marching_cubes(SS,GV,side(0),side(1),side(2),SV,SF);
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::copyleft::offset_surface<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, double, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, double, Eigen::Matrix<int, 1, 3, 1, 1, 3>::Scalar, igl::SignedDistanceType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
template void igl::copyleft::offset_surface<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, float, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, float, Eigen::Matrix<int, 1, 3, 1, 1, 3>::Scalar, igl::SignedDistanceType const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
template void igl::copyleft::offset_surface<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3>, 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&, double, Eigen::Matrix<int, 1, 3, 1, 1, 3>::Scalar, igl::SignedDistanceType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
#endif
-54
View File
@@ -1,54 +0,0 @@
#ifndef IGL_COPYLEFT_OFFSET_SURFACE_H
#define IGL_COPYLEFT_OFFSET_SURFACE_H
#include "../igl_inline.h"
#include "../signed_distance.h"
#include <Eigen/Core>
namespace igl
{
namespace copyleft
{
// Compute a triangulated offset surface using matching cubes on a grid of
// signed distance values from the input triangle mesh.
//
// Inputs:
// V #V by 3 list of mesh vertex positions
// F #F by 3 list of mesh triangle indices into V
// isolevel iso level to extract (signed distance: negative inside)
// s number of grid cells along longest side (controls resolution)
// signed_distance_type type of signing to use (see
// ../signed_distance.h)
// Outputs:
// SV #SV by 3 list of output surface mesh vertex positions
// SF #SF by 3 list of output mesh triangle indices into SV
// GV #GV=side(0)*side(1)*side(2) by 3 list of grid cell centers
// side list of number of grid cells in x, y, and z directions
// S #GV by 3 list of signed distance values _near_ `isolevel` ("far"
// from `isolevel` these values are incorrect)
//
template <
typename DerivedV,
typename DerivedF,
typename isolevelType,
typename DerivedSV,
typename DerivedSF,
typename DerivedGV,
typename Derivedside,
typename DerivedS>
void offset_surface(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F,
const isolevelType isolevel,
const typename Derivedside::Scalar s,
const SignedDistanceType & signed_distance_type,
Eigen::PlainObjectBase<DerivedSV> & SV,
Eigen::PlainObjectBase<DerivedSF> & SF,
Eigen::PlainObjectBase<DerivedGV> & GV,
Eigen::PlainObjectBase<Derivedside> & side,
Eigen::PlainObjectBase<DerivedS> & S);
}
}
#ifndef IGL_STATIC_LIBRARY
# include "offset_surface.cpp"
#endif
#endif
-41
View File
@@ -1,41 +0,0 @@
#ifndef IGL_COPYLEFT_SWEPT_VOLUME_H
#define IGL_COPYLEFT_SWEPT_VOLUME_H
#include "../igl_inline.h"
#include <Eigen/Core>
#include <Eigen/Geometry>
namespace igl
{
namespace copyleft
{
// Compute the surface of the swept volume of a solid object with surface
// (V,F) mesh under going rigid motion.
//
// Inputs:
// V #V by 3 list of mesh positions in reference pose
// F #F by 3 list of mesh indices into V
// transform function handle so that transform(t) returns the rigid
// transformation at time t∈[0,1]
// steps number of time steps: steps=3 --> t∈{0,0.5,1}
// grid_res number of grid cells on the longest side containing the
// motion (isolevel+1 cells will also be added on each side as padding)
// isolevel distance level to be contoured as swept volume
// Outputs:
// SV #SV by 3 list of mesh positions of the swept surface
// SF #SF by 3 list of mesh faces into SV
IGL_INLINE void swept_volume(
const Eigen::MatrixXd & V,
const Eigen::MatrixXi & F,
const std::function<Eigen::Affine3d(const double t)> & transform,
const size_t steps,
const size_t grid_res,
const size_t isolevel,
Eigen::MatrixXd & SV,
Eigen::MatrixXi & SF);
}
}
#ifndef IGL_STATIC_LIBRARY
# include "swept_volume.cpp"
#endif
#endif
@@ -13,120 +13,6 @@
// STL includes
#include <iostream>
IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
const tetgenio & out,
std::vector<std::vector<REAL > > & V,
std::vector<std::vector<int> > & T,
std::vector<std::vector<int > > & F,
std::vector<std::vector<REAL > >& R,
std::vector<std::vector<int > >& N,
std::vector<std::vector<int > >& PT,
std::vector<std::vector<int > >& FT,
size_t & nR )
{
using namespace std;
// process points
if(out.pointlist == NULL)
{
cerr<<"^tetgenio_to_tetmesh Error: point list is NULL\n"<<endl;
return false;
}
V.resize(out.numberofpoints,vector<REAL>(3));
// loop over points
for(int i = 0;i < out.numberofpoints; i++)
{
V[i][0] = out.pointlist[i*3+0];
V[i][1] = out.pointlist[i*3+1];
V[i][2] = out.pointlist[i*3+2];
}
// process tets
if(out.tetrahedronlist == NULL)
{
cerr<<"^tetgenio_to_tetmesh Error: tet list is NULL\n"<<endl;
return false;
}
// When would this not be 4?
assert(out.numberofcorners == 4);
T.resize(out.numberoftetrahedra,vector<int>(out.numberofcorners));
int min_index = 1e7;
int max_index = -1e7;
// loop over tetrahedra
for(int i = 0; i < out.numberoftetrahedra; i++)
{
for(int j = 0; j<out.numberofcorners; j++)
{
int index = out.tetrahedronlist[i * out.numberofcorners + j];
T[i][j] = index;
min_index = (min_index > index ? index : min_index);
max_index = (max_index < index ? index : max_index);
}
}
assert(min_index >= 0);
assert(max_index >= 0);
assert(max_index < (int)V.size());
cout<<out.numberoftrifaces<<endl;
// When would this not be 4?
F.clear();
// loop over tetrahedra
for(int i = 0; i < out.numberoftrifaces; i++)
{
if(out.trifacemarkerlist[i]>=0)
{
vector<int> face(3);
for(int j = 0; j<3; j++)
{
face[j] = out.trifacelist[i * 3 + j];
}
F.push_back(face);
}
}
R.resize(out.numberoftetrahedra, vector<REAL>(1));
unordered_map<REAL, REAL> hashUniqueRegions;
for(size_t i = 0; i < out.numberoftetrahedra; i++)
{
R[i][0] = out.tetrahedronattributelist[i];
hashUniqueRegions[R[i][0]] = i;
}
// extract region marks
nR = hashUniqueRegions.size();
// extract neighbor list
N.resize(out.numberoftetrahedra, vector<int>(4));
for (size_t i = 0; i < out.numberoftetrahedra; i++)
{
for (size_t j = 0; j < 4; j++)
N[i][j] = out.neighborlist[i * 4 + j];
}
// extract point 2 tetrahedron list
PT.resize(out.numberofpoints, vector<int>(1));
for (size_t i = 0; i < out.numberofpoints; i++)
{
PT[i][0] = out.point2tetlist[i];
}
//extract face to tetrahedron list
FT.resize(out.numberoftrifaces, vector<int>(2));
int triface;
for (size_t i = 0; i < out.numberoftrifaces; i++)
{
for (size_t j = 0; j < 2; j++)
{
FT[i][j] = out.face2tetlist[0];
}
}
return true;
}
IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
const tetgenio & out,
std::vector<std::vector<REAL > > & V,
@@ -196,12 +82,13 @@ IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
return true;
}
template <typename DerivedV, typename DerivedT>
IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
const tetgenio & out,
std::vector<std::vector<REAL > > & V,
std::vector<std::vector<int> > & T)
Eigen::PlainObjectBase<DerivedV>& V,
Eigen::PlainObjectBase<DerivedT>& T)
{
std::vector<std::vector<int> > F;
Eigen::Matrix<typename DerivedT::Scalar,Eigen::Dynamic,3> F;
return tetgenio_to_tetmesh(out,V,T,F);
}
@@ -242,16 +129,151 @@ IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
return true;
}
template <typename DerivedV, typename DerivedT>
IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
const tetgenio & out,
Eigen::PlainObjectBase<DerivedV>& V,
Eigen::PlainObjectBase<DerivedT>& T)
std::vector<std::vector<REAL > > & V,
std::vector<std::vector<int> > & T)
{
Eigen::Matrix<typename DerivedT::Scalar,Eigen::Dynamic,3> F;
std::vector<std::vector<int> > F;
return tetgenio_to_tetmesh(out,V,T,F);
}
IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
const tetgenio & out,
std::vector<std::vector<REAL > > & V,
std::vector<std::vector<int> > & T,
std::vector<std::vector<int > > & F,
std::vector<std::vector<REAL > >& R,
std::vector<std::vector<int > >& N,
std::vector<std::vector<int > >& PT,
std::vector<std::vector<int > >& FT,
size_t & nR )
{
using namespace std;
// process points
if(out.pointlist == NULL)
{
cerr<<"^tetgenio_to_tetmesh Error: point list is NULL\n"<<endl;
return false;
}
V.resize(out.numberofpoints,vector<REAL>(3));
// loop over points
for(int i = 0;i < out.numberofpoints; i++)
{
V[i][0] = out.pointlist[i*3+0];
V[i][1] = out.pointlist[i*3+1];
V[i][2] = out.pointlist[i*3+2];
}
// process tets
if(out.tetrahedronlist == NULL)
{
cerr<<"^tetgenio_to_tetmesh Error: tet list is NULL\n"<<endl;
return false;
}
// When would this not be 4?
assert(out.numberofcorners == 4);
T.resize(out.numberoftetrahedra,vector<int>(out.numberofcorners));
int min_index = 1e7;
int max_index = -1e7;
// loop over tetrahedra
for(int i = 0; i < out.numberoftetrahedra; i++)
{
for(int j = 0; j<out.numberofcorners; j++)
{
int index = out.tetrahedronlist[i * out.numberofcorners + j];
T[i][j] = index;
min_index = (min_index > index ? index : min_index);
max_index = (max_index < index ? index : max_index);
}
}
assert(min_index >= 0);
assert(max_index >= 0);
assert(max_index < (int)V.size());
// When would this not be 4?
F.clear();
// loop over tetrahedra
for(int i = 0; i < out.numberoftrifaces; i++)
{
if(out.trifacemarkerlist[i]>=0)
{
vector<int> face(3);
for(int j = 0; j<3; j++)
{
face[j] = out.trifacelist[i * 3 + j];
}
F.push_back(face);
}
}
if(out.tetrahedronattributelist)
{
R.resize(out.numberoftetrahedra, vector<REAL>(1));
unordered_map<REAL, REAL> hashUniqueRegions;
for(size_t i = 0; i < out.numberoftetrahedra; i++)
{
R[i][0] = out.tetrahedronattributelist[i];
hashUniqueRegions[R[i][0]] = i;
}
// extract region marks
nR = hashUniqueRegions.size();
}else
{
R.clear();
nR = 0;
}
// extract neighbor list
if(out.neighborlist)
{
N.resize(out.numberoftetrahedra, vector<int>(4));
for (size_t i = 0; i < out.numberoftetrahedra; i++)
{
for (size_t j = 0; j < 4; j++)
N[i][j] = out.neighborlist[i * 4 + j];
}
}else
{
N.clear();
}
// extract point 2 tetrahedron list
if(out.point2tetlist)
{
PT.resize(out.numberofpoints, vector<int>(1));
for (size_t i = 0; i < out.numberofpoints; i++)
{
PT[i][0] = out.point2tetlist[i];
}
}else
{
PT.clear();
}
//extract face to tetrahedron list
if(out.face2tetlist)
{
FT.resize(out.numberoftrifaces, vector<int>(2));
int triface;
for (size_t i = 0; i < out.numberoftrifaces; i++)
{
for (size_t j = 0; j < 2; j++)
{
FT[i][j] = out.face2tetlist[0];
}
}
}else
{
FT.clear();
}
return true;
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template bool igl::copyleft::tetgen::tetgenio_to_tetmesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(tetgenio const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
@@ -35,6 +35,7 @@ namespace igl
std::vector<std::vector<REAL > > & V,
std::vector<std::vector<int> > & T,
std::vector<std::vector<int> > & F);
IGL_INLINE bool tetgenio_to_tetmesh(
const tetgenio & out,
std::vector<std::vector<REAL > > & V,
@@ -50,6 +51,7 @@ namespace igl
Eigen::PlainObjectBase<DerivedV>& V,
Eigen::PlainObjectBase<DerivedT>& T,
Eigen::PlainObjectBase<DerivedF>& F);
template <typename DerivedV, typename DerivedT>
IGL_INLINE bool tetgenio_to_tetmesh(
const tetgenio & out,
+195 -194
View File
@@ -18,6 +18,200 @@
#include <cassert>
#include <iostream>
IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
const std::vector<std::vector<REAL > > & V,
const std::vector<std::vector<int> > & F,
const std::string switches,
std::vector<std::vector<REAL > > & TV,
std::vector<std::vector<int > > & TT,
std::vector<std::vector<int> > & TF)
{
using namespace std;
tetgenio in,out;
bool success;
success = mesh_to_tetgenio(V,F,in);
if(!success)
{
return -1;
}
try
{
char * cswitches = new char[switches.size() + 1];
std::strcpy(cswitches,switches.c_str());
::tetrahedralize(cswitches,&in, &out);
delete[] cswitches;
}catch(int e)
{
cerr<<"^"<<__FUNCTION__<<": TETGEN CRASHED... KABOOOM!!!"<<endl;
return 1;
}
if(out.numberoftetrahedra == 0)
{
cerr<<"^"<<__FUNCTION__<<": Tetgen failed to create tets"<<endl;
return 2;
}
success = tetgenio_to_tetmesh(out,TV,TT,TF);
if(!success)
{
return -1;
}
boundary_facets(TT,TF);
return 0;
}
template <
typename DerivedV,
typename DerivedF,
typename DerivedTV,
typename DerivedTT,
typename DerivedTF>
IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
const std::string switches,
Eigen::PlainObjectBase<DerivedTV>& TV,
Eigen::PlainObjectBase<DerivedTT>& TT,
Eigen::PlainObjectBase<DerivedTF>& TF)
{
using namespace std;
vector<vector<REAL> > vV,vTV;
vector<vector<int> > vF,vTT,vTF;
matrix_to_list(V,vV);
matrix_to_list(F,vF);
int e = tetrahedralize(vV,vF,switches,vTV,vTT,vTF);
if(e == 0)
{
bool TV_rect = list_to_matrix(vTV,TV);
if(!TV_rect)
{
return 3;
}
bool TT_rect = list_to_matrix(vTT,TT);
if(!TT_rect)
{
return 3;
}
bool TF_rect = list_to_matrix(vTF,TF);
if(!TF_rect)
{
return 3;
}
}
return e;
}
template <
typename DerivedV,
typename DerivedF,
typename DerivedVM,
typename DerivedFM,
typename DerivedTV,
typename DerivedTT,
typename DerivedTF,
typename DerivedTM>
IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedVM>& VM,
const Eigen::MatrixBase<DerivedFM>& FM,
const std::string switches,
Eigen::PlainObjectBase<DerivedTV>& TV,
Eigen::PlainObjectBase<DerivedTT>& TT,
Eigen::PlainObjectBase<DerivedTF>& TF,
Eigen::PlainObjectBase<DerivedTM>& TM)
{
using namespace std;
vector<vector<REAL> > vV,vTV;
vector<vector<int> > vF,vTT,vTF;
vector<int> vTM;
matrix_to_list(V,vV);
matrix_to_list(F,vF);
vector<int> vVM = matrix_to_list(VM);
vector<int> vFM = matrix_to_list(FM);
int e = tetrahedralize(vV,vF,vVM,vFM,switches,vTV,vTT,vTF,vTM);
if(e == 0)
{
bool TV_rect = list_to_matrix(vTV,TV);
if(!TV_rect)
{
return false;
}
bool TT_rect = list_to_matrix(vTT,TT);
if(!TT_rect)
{
return false;
}
bool TF_rect = list_to_matrix(vTF,TF);
if(!TF_rect)
{
return false;
}
bool TM_rect = list_to_matrix(vTM,TM);
if(!TM_rect)
{
return false;
}
}
return e;
}
IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
const std::vector<std::vector<REAL > > & V,
const std::vector<std::vector<int> > & F,
const std::vector<int> & VM,
const std::vector<int> & FM,
const std::string switches,
std::vector<std::vector<REAL > > & TV,
std::vector<std::vector<int > > & TT,
std::vector<std::vector<int> > & TF,
std::vector<int> & TM)
{
using namespace std;
tetgenio in,out;
bool success;
success = mesh_to_tetgenio(V,F,in);
if(!success)
{
return -1;
}
in.pointmarkerlist = new int[VM.size()];
for (int i = 0; i < VM.size(); ++i) {
in.pointmarkerlist[i] = VM[i];
}
// These have already been created in mesh_to_tetgenio.
// Reset them here.
for (int i = 0; i < FM.size(); ++i) {
in.facetmarkerlist[i] = FM[i];
}
try
{
char * cswitches = new char[switches.size() + 1];
std::strcpy(cswitches,switches.c_str());
::tetrahedralize(cswitches,&in, &out);
delete[] cswitches;
}catch(int e)
{
cerr<<"^"<<__FUNCTION__<<": TETGEN CRASHED... KABOOOM!!!"<<endl;
return 1;
}
if(out.numberoftetrahedra == 0)
{
cerr<<"^"<<__FUNCTION__<<": Tetgen failed to create tets"<<endl;
return 2;
}
success = tetgenio_to_tetmesh(out,TV,TT,TF);
if(!success)
{
return -1;
}
TM.resize(out.numberofpoints);
for (int i = 0; i < out.numberofpoints; ++i) {
TM[i] = out.pointmarkerlist[i];
}
boundary_facets(TT,TF);
return 0;
}
IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
const std::vector<std::vector<REAL > > & V,
@@ -143,203 +337,10 @@ IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
return e;
}
IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
const std::vector<std::vector<REAL > > & V,
const std::vector<std::vector<int> > & F,
const std::string switches,
std::vector<std::vector<REAL > > & TV,
std::vector<std::vector<int > > & TT,
std::vector<std::vector<int> > & TF)
{
using namespace std;
tetgenio in,out;
bool success;
success = mesh_to_tetgenio(V,F,in);
if(!success)
{
return -1;
}
try
{
char * cswitches = new char[switches.size() + 1];
std::strcpy(cswitches,switches.c_str());
::tetrahedralize(cswitches,&in, &out);
delete[] cswitches;
}catch(int e)
{
cerr<<"^"<<__FUNCTION__<<": TETGEN CRASHED... KABOOOM!!!"<<endl;
return 1;
}
if(out.numberoftetrahedra == 0)
{
cerr<<"^"<<__FUNCTION__<<": Tetgen failed to create tets"<<endl;
return 2;
}
success = tetgenio_to_tetmesh(out,TV,TT,TF);
if(!success)
{
return -1;
}
boundary_facets(TT,TF);
return 0;
}
template <
typename DerivedV,
typename DerivedF,
typename DerivedTV,
typename DerivedTT,
typename DerivedTF>
IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
const std::string switches,
Eigen::PlainObjectBase<DerivedTV>& TV,
Eigen::PlainObjectBase<DerivedTT>& TT,
Eigen::PlainObjectBase<DerivedTF>& TF)
{
using namespace std;
vector<vector<REAL> > vV,vTV;
vector<vector<int> > vF,vTT,vTF;
matrix_to_list(V,vV);
matrix_to_list(F,vF);
int e = tetrahedralize(vV,vF,switches,vTV,vTT,vTF);
if(e == 0)
{
bool TV_rect = list_to_matrix(vTV,TV);
if(!TV_rect)
{
return 3;
}
bool TT_rect = list_to_matrix(vTT,TT);
if(!TT_rect)
{
return 3;
}
bool TF_rect = list_to_matrix(vTF,TF);
if(!TF_rect)
{
return 3;
}
}
return e;
}
template <
typename DerivedV,
typename DerivedF,
typename DerivedVM,
typename DerivedFM,
typename DerivedTV,
typename DerivedTT,
typename DerivedTF,
typename DerivedTM>
IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedVM>& VM,
const Eigen::MatrixBase<DerivedFM>& FM,
const std::string switches,
Eigen::PlainObjectBase<DerivedTV>& TV,
Eigen::PlainObjectBase<DerivedTT>& TT,
Eigen::PlainObjectBase<DerivedTF>& TF,
Eigen::PlainObjectBase<DerivedTM>& TM)
{
using namespace std;
vector<vector<REAL> > vV,vTV;
vector<vector<int> > vF,vTT,vTF;
vector<int> vTM;
matrix_to_list(V,vV);
matrix_to_list(F,vF);
vector<int> vVM = matrix_to_list(VM);
vector<int> vFM = matrix_to_list(FM);
int e = tetrahedralize(vV,vF,vVM,vFM,switches,vTV,vTT,vTF,vTM);
if(e == 0)
{
bool TV_rect = list_to_matrix(vTV,TV);
if(!TV_rect)
{
return false;
}
bool TT_rect = list_to_matrix(vTT,TT);
if(!TT_rect)
{
return false;
}
bool TF_rect = list_to_matrix(vTF,TF);
if(!TF_rect)
{
return false;
}
bool TM_rect = list_to_matrix(vTM,TM);
if(!TM_rect)
{
return false;
}
}
return e;
}
IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
const std::vector<std::vector<REAL > > & V,
const std::vector<std::vector<int> > & F,
const std::vector<int> & VM,
const std::vector<int> & FM,
const std::string switches,
std::vector<std::vector<REAL > > & TV,
std::vector<std::vector<int > > & TT,
std::vector<std::vector<int> > & TF,
std::vector<int> & TM)
{
using namespace std;
tetgenio in,out;
bool success;
success = mesh_to_tetgenio(V,F,in);
if(!success)
{
return -1;
}
in.pointmarkerlist = new int[VM.size()];
for (int i = 0; i < VM.size(); ++i) {
in.pointmarkerlist[i] = VM[i];
}
// These have already been created in mesh_to_tetgenio.
// Reset them here.
for (int i = 0; i < FM.size(); ++i) {
in.facetmarkerlist[i] = FM[i];
}
try
{
char * cswitches = new char[switches.size() + 1];
std::strcpy(cswitches,switches.c_str());
::tetrahedralize(cswitches,&in, &out);
delete[] cswitches;
}catch(int e)
{
cerr<<"^"<<__FUNCTION__<<": TETGEN CRASHED... KABOOOM!!!"<<endl;
return 1;
}
if(out.numberoftetrahedra == 0)
{
cerr<<"^"<<__FUNCTION__<<": Tetgen failed to create tets"<<endl;
return 2;
}
success = tetgenio_to_tetmesh(out,TV,TT,TF);
if(!success)
{
return -1;
}
TM.resize(out.numberofpoints);
for (int i = 0; i < out.numberofpoints; ++i) {
TM[i] = out.pointmarkerlist[i];
}
boundary_facets(TT,TF);
return 0;
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template int igl::copyleft::tetgen::tetrahedralize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
template int igl::copyleft::tetgen::tetrahedralize<Eigen::Matrix<double, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, 1, 0, -1, 1>,Eigen::Matrix<int, -1, 1, 0, -1, 1>,Eigen::Matrix<double, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, 1, 0, -1, 1> >(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<int, -1, 1, 0, -1, 1> > &,const Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > &,const std::basic_string<char, std::char_traits<char>, std::allocator<char> >,Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > &,Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > &,Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > &, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > &);
template int igl::copyleft::tetgen::tetrahedralize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
template int igl::copyleft::tetgen::tetrahedralize<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::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, unsigned long&);
#endif
+46 -56
View File
@@ -15,7 +15,7 @@
#ifndef TETLIBRARY
#define TETLIBRARY
#endif
#include "tetgen.h" // Defined REAL
#include <tetgen.h> // Defined REAL
namespace igl
{
@@ -68,12 +68,12 @@ namespace igl
Eigen::PlainObjectBase<DerivedTT>& TT,
Eigen::PlainObjectBase<DerivedTF>& TF);
// Mesh the interior of a surface mesh (V,F) using tetgen
// Mesh the interior of a surface mesh (V,F) using tetgen
//
// Inputs:
// V #V by 3 vertex position list
// F #F list of polygon face indices into V (0-indexed)
// M #V list of markers for vertices
// M #V list of markers for vertices
// switches string of tetgen options (See tetgen documentation) e.g.
// "pq1.414a0.01" tries to mesh the interior of a given surface with
// quality and area constraints
@@ -82,7 +82,7 @@ namespace igl
// TV #V by 3 vertex position list
// TT #T by 4 list of tet face indices
// TF #F by 3 list of triangle face indices
// TM #V list of markers for vertices
// TM #V list of markers for vertices
// Returns status:
// 0 success
// 1 tetgen threw exception
@@ -92,14 +92,13 @@ namespace igl
IGL_INLINE int tetrahedralize(
const std::vector<std::vector<REAL > > & V,
const std::vector<std::vector<int> > & F,
const std::vector<int> & VM,
const std::vector<int> & FM,
const std::vector<int> & VM,
const std::vector<int> & FM,
const std::string switches,
std::vector<std::vector<REAL > > & TV,
std::vector<std::vector<int > > & TT,
std::vector<std::vector<int> > & TF,
std::vector<int> & TM);
std::vector<int> & TM);
// Wrapper with Eigen types
// Templates:
// DerivedV real-value: i.e. from MatrixXd
@@ -107,8 +106,8 @@ namespace igl
template <
typename DerivedV,
typename DerivedF,
typename DerivedVM,
typename DerivedFM,
typename DerivedVM,
typename DerivedFM,
typename DerivedTV,
typename DerivedTT,
typename DerivedTF,
@@ -123,16 +122,13 @@ namespace igl
Eigen::PlainObjectBase<DerivedTT>& TT,
Eigen::PlainObjectBase<DerivedTF>& TF,
Eigen::PlainObjectBase<DerivedTM>& TM);
// Mesh the interior of a surface mesh (V,F) using tetgen
//
// Inputs:
// V #V by 3 vertex position list
// F #F list of polygon face indices into V (0-indexed)
// H #H by 3 list of seed points inside holes
// R #R by 5 list of region attributes
// R #R by 5 list of region attributes
// switches string of tetgen options (See tetgen documentation) e.g.
// "pq1.414a0.01" tries to mesh the interior of a given surface with
// quality and area constraints
@@ -141,64 +137,58 @@ namespace igl
// TV #V by 3 vertex position list
// TT #T by 4 list of tet face indices
// TF #F by 3 list of triangle face indices
// TR #T list of region ID for each tetrahedron
// TR #T list of region ID for each tetrahedron
// TN #T by 4 list of indices neighbors for each tetrahedron
// PT #V list of incident tetrahedron for a vertex
// FT #F by 2 list of tetrahedrons sharing a triface
// FT #F by 2 list of tetrahedrons sharing a triface
// numRegions Number of regions in output mesh
// Returns status:
// 0 success
// 1 tetgen threw exception
// 2 tetgen did not crash but could not create any tets (probably there are
// holes, duplicate faces etc.)
// -1 other error
IGL_INLINE int tetrahedralize(
const std::vector<std::vector<REAL> > &V,
const std::vector<std::vector<int> > &F,
const std::vector<std::vector<REAL> > &H,
const std::vector<std::vector<REAL> > &R,
const std::string switches,
std::vector<std::vector<REAL > > & TV,
std::vector<std::vector<int > > & TT,
std::vector<std::vector<int > > & TF,
std::vector<std::vector<REAL > > &TR,
std::vector<std::vector<int > > &TN,
std::vector<std::vector<int > > &PT,
std::vector<std::vector<int > > &FT,
size_t & numRegions);
IGL_INLINE int tetrahedralize(
const std::vector<std::vector<REAL> > &V,
const std::vector<std::vector<int> > &F,
const std::vector<std::vector<REAL> > &H,
const std::vector<std::vector<REAL> > &R,
const std::string switches,
std::vector<std::vector<REAL > > & TV,
std::vector<std::vector<int > > & TT,
std::vector<std::vector<int > > & TF,
std::vector<std::vector<REAL > > &TR,
std::vector<std::vector<int > > &TN,
std::vector<std::vector<int > > &PT,
std::vector<std::vector<int > > &FT,
size_t & numRegions);
// Wrapper with Eigen types
// Templates:
// DerivedV real-value: i.e. from MatrixXd
// DerivedF integer-value: i.e. from MatrixXi
// DerivedF integer-value: i.e. from MatrixXi
template <
typename DerivedV,
typename DerivedF,
typename DerivedH,
typename DerivedR,
typename DerivedTV,
typename DerivedTT,
typename DerivedTF,
typename DerivedTR>
typename DerivedF,
typename DerivedH,
typename DerivedR,
typename DerivedTV,
typename DerivedTT,
typename DerivedTF,
typename DerivedTR>
IGL_INLINE int tetrahedralize(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedH>& H,
const Eigen::MatrixBase<DerivedR>& R,
const std::string switches,
Eigen::PlainObjectBase<DerivedTV>& TV,
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedH>& H,
const Eigen::MatrixBase<DerivedR>& R,
const std::string switches,
Eigen::PlainObjectBase<DerivedTV>& TV,
Eigen::PlainObjectBase<DerivedTT>& TT,
Eigen::PlainObjectBase<DerivedTF>& TF,
Eigen::PlainObjectBase<DerivedTR>& TR,
Eigen::PlainObjectBase<DerivedTT>& TN,
Eigen::PlainObjectBase<DerivedTT>& PT,
Eigen::PlainObjectBase<DerivedTT>& FT,
size_t & numRegions);
Eigen::PlainObjectBase<DerivedTF>& TF,
Eigen::PlainObjectBase<DerivedTR>& TR,
Eigen::PlainObjectBase<DerivedTT>& TN,
Eigen::PlainObjectBase<DerivedTT>& PT,
Eigen::PlainObjectBase<DerivedTT>& FT,
size_t & numRegions);
}
}
}
+143
View File
@@ -78,9 +78,152 @@ IGL_INLINE void igl::cotmatrix(
L.setFromTriplets(IJV.begin(),IJV.end());
}
#include "massmatrix.h"
#include "pinv.h"
#include "cotmatrix_entries.h"
#include "diag.h"
#include "massmatrix.h"
#include <Eigen/Geometry>
template <
typename DerivedV,
typename DerivedI,
typename DerivedC,
typename Scalar>
IGL_INLINE void igl::cotmatrix(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedI> & I,
const Eigen::MatrixBase<DerivedC> & C,
Eigen::SparseMatrix<Scalar>& L,
Eigen::SparseMatrix<Scalar>& M,
Eigen::SparseMatrix<Scalar>& P)
{
typedef Eigen::Matrix<Scalar,1,3> RowVector3S;
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> MatrixXS;
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,1> VectorXS;
typedef Eigen::Index Index;
// number of vertices
const Index n = V.rows();
// number of polyfaces
const Index m = C.size()-1;
assert(V.cols() == 2 || V.cols() == 3);
std::vector<Eigen::Triplet<Scalar> > Lfijv;
std::vector<Eigen::Triplet<Scalar> > Mfijv;
std::vector<Eigen::Triplet<Scalar> > Pijv;
// loop over vertices; set identity for original vertices
for(Index i = 0;i<V.rows();i++) { Pijv.emplace_back(i,i,1); }
// loop over faces
for(Index p = 0;p<C.size()-1;p++)
{
// number of faces/vertices in this simple polygon
const Index np = C(p+1)-C(p);
// Working "local" list of vertices; last vertex is new one
// this needs to have 3 columns so Eigen doesn't complain about cross
// products below.
Eigen::Matrix<Scalar,Eigen::Dynamic,3> X = decltype(X)::Zero(np+1,3);
for(Index i = 0;i<np;i++){ X.row(i).head(V.cols()) = V.row(I(C(p)+i)); };
// determine weights definig position of inserted vertex
{
MatrixXS A = decltype(A)::Zero(np+1,np);
// My equation (38) would be A w = b.
VectorXS b = decltype(b)::Zero(np+1);
for(Index k = 0;k<np;k++)
{
const RowVector3S Xkp1mk = X.row((k+1)%np)-X.row(k);
const RowVector3S Xkp1mkck = Xkp1mk.cross(X.row(k));
for(Index i = 0;i<np;i++)
{
b(i) -= 2.*(X.row(i).cross(Xkp1mk)).dot(Xkp1mkck);
for(Index j = 0;j<np;j++)
{
A(i,j) += 2.*(X.row(j).cross(Xkp1mk)).dot(X.row(i).cross(Xkp1mk));
}
}
}
A.row(np).setConstant(1);
b(np) = 1;
const VectorXS w =
Eigen::CompleteOrthogonalDecomposition<Eigen::MatrixXd>(A).solve(b);
X.row(np) = w.transpose()*X.topRows(np);
// scatter w into new row of P
for(Index i = 0;i<np;i++) { Pijv.emplace_back(n+p,I(C(p)+i),w(i)); }
}
// "local" fan of faces. These could be statically cached, but this will
// not be the bottleneck.
Eigen::MatrixXi F(np,3);
for(Index i = 0;i<np;i++)
{
F(i,0) = i;
F(i,1) = (i+1)%np;
F(i,2) = np;
}
// Cotangent contributions
MatrixXS K;
igl::cotmatrix_entries(X,F,K);
// Massmatrix entried
VectorXS Mp;
{
Eigen::SparseMatrix<Scalar> M;
igl::massmatrix(X,F,igl::MASSMATRIX_TYPE_DEFAULT,M);
Mp = M.diagonal();
}
// Scatter into fine Laplacian and mass matrices
const auto J = [&n,&np,&p,&I,&C](Index i)->Index{return i==np?n+p:I(C(p)+i);};
// Should just build Mf as a vector...
for(Index i = 0;i<np+1;i++) { Mfijv.emplace_back(J(i),J(i),Mp(i)); }
// loop over faces
for(Index f = 0;f<np;f++)
{
for(Index c = 0;c<3;c++)
{
const Index i = F(f,(c+1)%3);
const Index j = F(f,(c+2)%3);
// symmetric off-diagonal
Lfijv.emplace_back(J(i),J(j),K(f,c));
Lfijv.emplace_back(J(j),J(i),K(f,c));
// diagonal
Lfijv.emplace_back(J(i),J(i),-K(f,c));
Lfijv.emplace_back(J(j),J(j),-K(f,c));
}
}
}
P.resize(n+m,n);
P.setFromTriplets(Pijv.begin(),Pijv.end());
Eigen::SparseMatrix<Scalar> Lf(n+m,n+m);
Lf.setFromTriplets(Lfijv.begin(),Lfijv.end());
Eigen::SparseMatrix<Scalar> Mf(n+m,n+m);
Mf.setFromTriplets(Mfijv.begin(),Mfijv.end());
L = P.transpose() * Lf * P;
// "unlumped" M
const Eigen::SparseMatrix<Scalar> PTMP = P.transpose() * Mf * P;
// Lump M
const VectorXS Mdiag = PTMP * VectorXS::Ones(n,1);
igl::diag(Mdiag,M);
MatrixXS Vf = P*V;
Eigen::MatrixXi Ff(I.size(),3);
{
Index f = 0;
for(Index p = 0;p<C.size()-1;p++)
{
const Index np = C(p+1)-C(p);
for(Index c = 0;c<np;c++)
{
Ff(f,0) = I(C(p)+c);
Ff(f,1) = I(C(p)+(c+1)%np);
Ff(f,2) = V.rows()+p;
f++;
}
}
assert(f == Ff.rows());
}
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::cotmatrix<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int>&, Eigen::SparseMatrix<double, 0, int>&, Eigen::SparseMatrix<double, 0, int>&);
// generated by autoexplicit.sh
template void igl::cotmatrix<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
template void igl::cotmatrix<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 4, 0, -1, 4>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> > const&, Eigen::SparseMatrix<double, 0, int>&);
template void igl::cotmatrix<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::SparseMatrix<double, 0, int>&);
+25
View File
@@ -48,6 +48,31 @@ namespace igl
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F,
Eigen::SparseMatrix<Scalar>& L);
// Cotangent Laplacian (and mass matrix) for polygon meshes according to
// "Polygon Laplacian Made Simple" [Bunge et al. 2020]
//
// Inputs:
// V #V by 3 list of mesh vertex positions
// 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:
// L #V by #V polygon Laplacian made simple matrix
// M #V by #V mass matrix
// P #V+#polygons by #V prolongation operator
template <
typename DerivedV,
typename DerivedI,
typename DerivedC,
typename Scalar>
IGL_INLINE void cotmatrix(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedI> & I,
const Eigen::MatrixBase<DerivedC> & C,
Eigen::SparseMatrix<Scalar>& L,
Eigen::SparseMatrix<Scalar>& M,
Eigen::SparseMatrix<Scalar>& P);
}
#ifndef IGL_STATIC_LIBRARY
+2
View File
@@ -136,6 +136,8 @@ IGL_INLINE void igl::cotmatrix_entries(
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::cotmatrix_entries<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
// generated by autoexplicit.sh
template void igl::cotmatrix_entries<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
// generated by autoexplicit.sh
template void igl::cotmatrix_entries<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
@@ -0,0 +1,189 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "cr_vector_curvature_correction.h"
#include "orient_halfedges.h"
#include "gaussian_curvature.h"
#include "squared_edge_lengths.h"
#include "doublearea.h"
#include "boundary_loop.h"
#include "internal_angles.h"
#include "PI.h"
template <typename DerivedV, typename DerivedF, typename DerivedE,
typename DerivedOE, typename ScalarK>
IGL_INLINE void
igl::cr_vector_curvature_correction(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarK>& K)
{
Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic>
l_sq;
squared_edge_lengths(V, F, l_sq);
cr_vector_curvature_correction_intrinsic(F, l_sq, E, oE, K);
}
template <typename DerivedV, typename DerivedF, typename DerivedE,
typename DerivedOE, typename ScalarK>
IGL_INLINE void
igl::cr_vector_curvature_correction(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
Eigen::PlainObjectBase<DerivedE>& E,
Eigen::PlainObjectBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarK>& K)
{
if(E.rows()!=F.rows() || E.cols()!=F.cols() || oE.rows()!=F.rows() ||
oE.cols()!=F.cols()) {
orient_halfedges(F, E, oE);
}
const Eigen::PlainObjectBase<DerivedE>& cE = E;
const Eigen::PlainObjectBase<DerivedOE>& coE = oE;
cr_vector_curvature_correction(V, F, cE, coE, K);
}
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
typename DerivedOE, typename ScalarK>
IGL_INLINE void
igl::cr_vector_curvature_correction_intrinsic(
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarK>& K)
{
Eigen::Matrix<typename DerivedL_sq::Scalar,Eigen::Dynamic,Eigen::Dynamic>
theta;
internal_angles_using_squared_edge_lengths(l_sq, theta);
cr_vector_curvature_correction_intrinsic(F, l_sq, theta, E, oE, K);
}
template <typename DerivedF, typename DerivedL_sq, typename Derivedtheta,
typename DerivedE, typename DerivedOE,
typename ScalarK>
IGL_INLINE void
igl::cr_vector_curvature_correction_intrinsic(
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
const Eigen::MatrixBase<Derivedtheta>& theta,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarK>& K)
{
// Compute the angle defect kappa, set it to 0 at the boundary
const typename DerivedF::Scalar n = F.maxCoeff() + 1;
Eigen::Matrix<typename DerivedL_sq::Scalar,Eigen::Dynamic,1> kappa(n);
kappa.setZero();
for(Eigen::Index i=0; i<F.rows(); ++i) {
for(int j=0; j<3; ++j) {
kappa(F(i,j)) -= theta(i,j);
}
}
kappa.array() += 2 * PI;
std::vector<std::vector<typename DerivedF::Scalar> > b;
boundary_loop(F, b);
for(const auto& loop : b) {
for(auto v : loop) {
kappa(v) = 0;
}
}
cr_vector_curvature_correction_intrinsic(F, l_sq, theta, kappa, E, oE, K);
}
template <typename DerivedF, typename DerivedL_sq, typename Derivedtheta,
typename Derivedkappa, typename DerivedE, typename DerivedOE,
typename ScalarK>
IGL_INLINE void
igl::cr_vector_curvature_correction_intrinsic(
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
const Eigen::MatrixBase<Derivedtheta>& theta,
const Eigen::MatrixBase<Derivedkappa>& kappa,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarK>& K)
{
assert(F.cols()==3 && "Faces have three vertices");
assert(E.rows()==F.rows() && E.cols()==F.cols() && oE.rows()==F.rows() &&
theta.rows()==F.rows() && theta.cols()==F.cols() &&
oE.cols()==F.cols() && "Wrong dimension in edge vectors");
assert(kappa.rows()==F.maxCoeff()+1 &&
"Wrong dimension in theta or kappa");
const Eigen::Index m = F.rows();
const typename DerivedE::Scalar nE = E.maxCoeff() + 1;
//Divide kappa by the actual angle sum to weigh consistently.
Derivedtheta angleSum = Derivedtheta::Zero(kappa.rows(), 1);
for(Eigen::Index i=0; i<F.rows(); ++i) {
for(int j=0; j<3; ++j) {
angleSum(F(i,j)) += theta(i,j);
}
}
const Eigen::Matrix<typename Derivedkappa::Scalar, Eigen::Dynamic, 1>
scaledKappa = kappa.array() / angleSum.array();
std::vector<Eigen::Triplet<ScalarK> > tripletList;
tripletList.reserve(10*3*m);
for(Eigen::Index f=0; f<m; ++f) {
for(int e=0; e<3; ++e) {
const ScalarK eij=l_sq(f,e), ejk=l_sq(f,(e+1)%3),
eki=l_sq(f,(e+2)%3); //These are squared quantities.
const ScalarK lens = sqrt(eij*eki);
const ScalarK o = oE(f,e)*oE(f,(e+2)%3);
const typename DerivedF::Scalar i=F(f,(e+1)%3), j=F(f,(e+2)%3), k=F(f,e);
const ScalarK ki=scaledKappa(i)*theta(f,(e+1)%3),
kj=scaledKappa(j)*theta(f,(e+2)%3), kk=scaledKappa(k)*theta(f,e);
const ScalarK costhetaidiv = (eij-ejk+eki)/(2.*lens);
const ScalarK sinthetaidiv = sqrt( (1.-pow(eij-ejk+eki,2)/
(4.*eij*eki)) );
const ScalarK Corrijij = (ki+kj+kk);
tripletList.emplace_back(E(f,e), E(f,e), Corrijij);
tripletList.emplace_back(E(f,e)+nE, E(f,e)+nE, Corrijij);
const ScalarK Corrijki = -o*(ki-kj-kk)*costhetaidiv;
tripletList.emplace_back(E(f,e), E(f,(e+2)%3), Corrijki);
tripletList.emplace_back(E(f,(e+2)%3), E(f,e), Corrijki);
tripletList.emplace_back(E(f,e)+nE, E(f,(e+2)%3)+nE, Corrijki);
tripletList.emplace_back(E(f,(e+2)%3)+nE, E(f,e)+nE, Corrijki);
const ScalarK Corrijkiperp = o*(ki-kj-kk)*sinthetaidiv;
tripletList.emplace_back(E(f,e), E(f,(e+2)%3)+nE, Corrijkiperp);
tripletList.emplace_back(E(f,(e+2)%3)+nE, E(f,e), Corrijkiperp);
tripletList.emplace_back(E(f,e)+nE, E(f,(e+2)%3), -Corrijkiperp);
tripletList.emplace_back(E(f,(e+2)%3), E(f,e)+nE, -Corrijkiperp);
}
}
K.resize(2*nE, 2*nE);
K.setFromTriplets(tripletList.begin(), tripletList.end());
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template void igl::cr_vector_curvature_correction_intrinsic<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
template void igl::cr_vector_curvature_correction<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::SparseMatrix<double, 0, int>&);
#endif
@@ -0,0 +1,115 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_CR_VECTOR_CURVATURE_CORRECTION_H
#define IGL_CR_VECTOR_CURVATURE_CORRECTION_H
#include "igl_inline.h"
#include <Eigen/Core>
#include <Eigen/Sparse>
namespace igl
{
// Computes the vector Crouzeix-Raviart curvature correction
// term of Oded Stein, Alec Jacobson, Max Wardetzky, Eitan
// Grinspun, 2020. "A Smoothness Energy without Boundary Distortion for
// Curved Surfaces", but using the basis functions by Oded Stein,
// Max Wardetzky, Alec Jacobson, Eitan Grinspun, 2020.
// "A Simple Discretization of the Vector Dirichlet Energy"
//
// Inputs:
// V, F: input mesh
// E: a mapping from each halfedge to each edge, as computed with
// orient_halfedges.
// will be computed if not provided.
// oE: the orientation of each halfedge compared to the orientation of the
// actual edge, as computed with orient_halfedges.
// will be computed if not provided.
//
// Outputs:
// K: computed curvature correction matrix
// E, oE: these are computed if they are not present, as described above
template <typename DerivedV, typename DerivedF, typename DerivedE,
typename DerivedOE, typename ScalarK>
IGL_INLINE void
cr_vector_curvature_correction(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarK>& K);
template <typename DerivedV, typename DerivedF, typename DerivedE,
typename DerivedOE, typename ScalarK>
IGL_INLINE void
cr_vector_curvature_correction(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
Eigen::PlainObjectBase<DerivedE>& E,
Eigen::PlainObjectBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarK>& K);
// Version that uses intrinsic quantities as input
//
// Inputs:
// F: input mesh connectivity
// l_sq: squared edge lengths of each halfedge
// theta: the tip angles at each halfedge
// kappa: the Gaussian curvature at each vertex
// E: a mapping from each halfedge to each edge.
// oE: the orientation of each halfedge compared to the orientation of the
// actual edge.
//
// Outputs:
// K: computed curvature correction matrix
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
typename DerivedOE, typename ScalarK>
IGL_INLINE void
cr_vector_curvature_correction_intrinsic(
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarK>& K);
template <typename DerivedF, typename DerivedL_sq, typename Derivedtheta,
typename DerivedE, typename DerivedOE,
typename ScalarK>
IGL_INLINE void
cr_vector_curvature_correction_intrinsic(
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
const Eigen::MatrixBase<Derivedtheta>& theta,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarK>& K);
template <typename DerivedF, typename DerivedL_sq, typename Derivedtheta,
typename Derivedkappa, typename DerivedE, typename DerivedOE,
typename ScalarK>
IGL_INLINE void
cr_vector_curvature_correction_intrinsic(
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
const Eigen::MatrixBase<Derivedtheta>& theta,
const Eigen::MatrixBase<Derivedkappa>& kappa,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarK>& K);
}
#ifndef IGL_STATIC_LIBRARY
# include "cr_vector_curvature_correction.cpp"
#endif
#endif
+128
View File
@@ -0,0 +1,128 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "cr_vector_laplacian.h"
#include <vector>
#include "orient_halfedges.h"
#include "doublearea.h"
#include "squared_edge_lengths.h"
template <typename DerivedV, typename DerivedF, typename DerivedE,
typename DerivedOE, typename ScalarL>
IGL_INLINE void
igl::cr_vector_laplacian(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarL>& L)
{
Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic>
l_sq;
squared_edge_lengths(V, F, l_sq);
cr_vector_laplacian_intrinsic(F, l_sq, E, oE, L);
}
template <typename DerivedV, typename DerivedF, typename DerivedE,
typename DerivedOE, typename ScalarL>
IGL_INLINE void
igl::cr_vector_laplacian(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
Eigen::PlainObjectBase<DerivedE>& E,
Eigen::PlainObjectBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarL>& L)
{
if(E.rows()!=F.rows() || E.cols()!=F.cols() || oE.rows()!=F.rows() ||
oE.cols()!=F.cols()) {
orient_halfedges(F, E, oE);
}
const Eigen::PlainObjectBase<DerivedE>& cE = E;
const Eigen::PlainObjectBase<DerivedOE>& coE = oE;
cr_vector_laplacian(V, F, cE, coE, L);
}
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
typename DerivedOE, typename ScalarL>
IGL_INLINE void
igl::cr_vector_laplacian_intrinsic(
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarL>& L)
{
Eigen::Matrix<typename DerivedL_sq::Scalar, Eigen::Dynamic, Eigen::Dynamic>
dA;
DerivedL_sq l_sqrt = l_sq.array().sqrt().matrix();
doublearea(l_sqrt, dA);
cr_vector_laplacian_intrinsic(F, l_sq, dA, E, oE, L);
}
template <typename DerivedF, typename DerivedL_sq, typename DeriveddA,
typename DerivedE, typename DerivedOE, typename ScalarL>
IGL_INLINE void
igl::cr_vector_laplacian_intrinsic(
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
const Eigen::MatrixBase<DeriveddA>& dA,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarL>& L)
{
assert(F.cols()==3 && "Faces have three vertices");
assert(E.rows()==F.rows() && E.cols()==F.cols() && oE.rows()==F.rows() &&
oE.cols()==F.cols() && "Wrong dimension in edge vectors");
assert(l_sq.rows()==F.rows() && l_sq.cols()==3 && "l_sq dimensions wrong");
assert(dA.size()==F.rows() && "dA dimensions wrong");
const Eigen::Index m = F.rows();
const typename DerivedE::Scalar nE = E.maxCoeff() + 1;
std::vector<Eigen::Triplet<ScalarL> > tripletList;
tripletList.reserve(10*3*m);
for(Eigen::Index f=0; f<m; ++f) {
for(int e=0; e<3; ++e) {
const ScalarL eij=l_sq(f,e), ejk=l_sq(f,(e+1)%3),
eki=l_sq(f,(e+2)%3); //These are squared quantities.
const ScalarL lens = sqrt(eij*eki);
const ScalarL o = oE(f,e)*oE(f,(e+2)%3);
tripletList.emplace_back(E(f,e), E(f,e), 2./dA(f) * eij);
tripletList.emplace_back(E(f,e)+nE, E(f,e)+nE, 2./dA(f) * eij);
const ScalarL Dijki = o * pow(eij-ejk+eki,2)/(2.*lens*dA(f));
tripletList.emplace_back(E(f,e), E(f,(e+2)%3), Dijki);
tripletList.emplace_back(E(f,(e+2)%3), E(f,e), Dijki);
tripletList.emplace_back(E(f,e)+nE, E(f,(e+2)%3)+nE, Dijki);
tripletList.emplace_back(E(f,(e+2)%3)+nE, E(f,e)+nE, Dijki);
const ScalarL Dijkiperp = -o * (eij-ejk+eki)/lens;
tripletList.emplace_back(E(f,e), E(f,(e+2)%3)+nE, Dijkiperp);
tripletList.emplace_back(E(f,(e+2)%3)+nE, E(f,e), Dijkiperp);
tripletList.emplace_back(E(f,e)+nE, E(f,(e+2)%3), -Dijkiperp);
tripletList.emplace_back(E(f,(e+2)%3), E(f,e)+nE, -Dijkiperp);
}
}
L.resize(2*nE, 2*nE);
L.setFromTriplets(tripletList.begin(), tripletList.end());
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template void igl::cr_vector_laplacian<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::SparseMatrix<double, 0, int>&);
template void igl::cr_vector_laplacian_intrinsic<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<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(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&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
#endif
+99
View File
@@ -0,0 +1,99 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_CR_VECTOR_LAPLACIAN_H
#define IGL_CR_VECTOR_LAPLACIAN_H
#include "igl_inline.h"
#include <Eigen/Core>
#include <Eigen/Sparse>
namespace igl
{
// Computes the CR vector Laplacian matrix.
// See Oded Stein, Max Wardetzky, Alec Jacobson, Eitan Grinspun, 2020.
// "A Simple Discretization of the Vector Dirichlet Energy"
//
// Inputs:
// V, F: input mesh
// E: a mapping from each halfedge to each edge, as computed with
// orient_halfedges.
// will be computed if not provided.
// oE: the orientation of each halfedge compared to the orientation of the
// actual edge, as computed with orient_halfedges.
// will be computed if not provided.
//
// Outputs:
// L: computed Laplacian matrix
// E, oE: these are computed if they are not present, as described above
template <typename DerivedV, typename DerivedF, typename DerivedE,
typename DerivedOE, typename ScalarL>
IGL_INLINE void
cr_vector_laplacian(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarL>& L);
template <typename DerivedV, typename DerivedF, typename DerivedE,
typename DerivedOE, typename ScalarL>
IGL_INLINE void
cr_vector_laplacian(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
Eigen::PlainObjectBase<DerivedE>& E,
Eigen::PlainObjectBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarL>& L);
// Version that uses intrinsic quantities as input
//
// Inputs:
// F: input mesh connectivity
// l_sq: squared edge lengths of each halfedge
// dA: double area of each face
// E: a mapping from each halfedge to each edge.
// oE: the orientation of each halfedge compared to the orientation of the
// actual edge.
//
// Outputs:
// L: computed Laplacian matrix
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
typename DerivedOE, typename ScalarL>
IGL_INLINE void
cr_vector_laplacian_intrinsic(
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarL>& L);
template <typename DerivedF, typename DerivedL_sq, typename DeriveddA,
typename DerivedE, typename DerivedOE, typename ScalarL>
IGL_INLINE void
cr_vector_laplacian_intrinsic(
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
const Eigen::MatrixBase<DeriveddA>& dA,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarL>& L);
}
#ifndef IGL_STATIC_LIBRARY
# include "cr_vector_laplacian.cpp"
#endif
#endif
+112
View File
@@ -0,0 +1,112 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "cr_vector_mass.h"
#include <vector>
#include "orient_halfedges.h"
#include "doublearea.h"
#include "squared_edge_lengths.h"
template <typename DerivedV, typename DerivedF, typename DerivedE,
typename DerivedOE, typename ScalarM>
IGL_INLINE void
igl::cr_vector_mass(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarM>& M)
{
Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic>
l_sq;
squared_edge_lengths(V, F, l_sq);
cr_vector_mass_intrinsic(F, l_sq, E, oE, M);
}
template <typename DerivedV, typename DerivedF, typename DerivedE,
typename DerivedOE, typename ScalarM>
IGL_INLINE void
igl::cr_vector_mass(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
Eigen::PlainObjectBase<DerivedE>& E,
Eigen::PlainObjectBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarM>& M)
{
if(E.rows()!=F.rows() || E.cols()!=F.cols() || oE.rows()!=F.rows() ||
oE.cols()!=F.cols()) {
orient_halfedges(F, E, oE);
}
const Eigen::PlainObjectBase<DerivedE>& cE = E;
const Eigen::PlainObjectBase<DerivedOE>& coE = oE;
cr_vector_mass(V, F, cE, coE, M);
}
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
typename DerivedOE, typename ScalarM>
IGL_INLINE void
igl::cr_vector_mass_intrinsic(
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarM>& M)
{
Eigen::Matrix<typename DerivedL_sq::Scalar, Eigen::Dynamic, Eigen::Dynamic>
dA;
DerivedL_sq l_sqrt = l_sq.array().sqrt().matrix();
doublearea(l_sqrt, dA);
cr_vector_mass_intrinsic(F, l_sq, dA, E, oE, M);
}
template <typename DerivedF, typename DerivedL_sq, typename DeriveddA,
typename DerivedE, typename DerivedOE, typename ScalarM>
IGL_INLINE void
igl::cr_vector_mass_intrinsic(
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
const Eigen::MatrixBase<DeriveddA>& dA,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarM>& M)
{
assert(F.cols()==3 && "Faces have three vertices");
assert(E.rows()==F.rows() && E.cols()==F.cols() && oE.rows()==F.rows() &&
oE.cols()==F.cols() && "Wrong dimension in edge vectors");
const Eigen::Index m = F.rows();
const typename DerivedE::Scalar nE = E.maxCoeff() + 1;
std::vector<Eigen::Triplet<ScalarM> > tripletList;
tripletList.reserve(2*3*m);
for(Eigen::Index f=0; f<m; ++f) {
for(int e=0; e<3; ++e) {
const typename DerivedF::Scalar v1=F(f,(e+1)%3), v2=F(f,(e+2)%3);
//Scaled
const ScalarM entry = dA(f) / 6;
tripletList.emplace_back(E(f,e), E(f,e), entry);
tripletList.emplace_back(E(f,e)+nE, E(f,e)+nE, entry);
}
}
M.resize(2*nE, 2*nE);
M.setFromTriplets(tripletList.begin(), tripletList.end());
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template void igl::cr_vector_mass<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::SparseMatrix<double, 0, int>&);
template void igl::cr_vector_mass_intrinsic<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<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(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&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
#endif
+100
View File
@@ -0,0 +1,100 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_CR_VECTOR_MASS
#define IGL_CR_VECTOR_MASS
#include "igl_inline.h"
#include <Eigen/Core>
#include <Eigen/Sparse>
namespace igl
{
// Computes the CR vector mass matrix, using an arrangement of all parallel
// degrees of freedom first, and all perpendicular degrees of freedom next.
// See Oded Stein, Max Wardetzky, Alec Jacobson, Eitan Grinspun, 2020.
// "A Simple Discretization of the Vector Dirichlet Energy"
//
// Inputs:
// V, F: input mesh
// E: a mapping from each halfedge to each edge, as computed with
// orient_halfedges.
// will be computed if not provided.
// oE: the orientation of each halfedge compared to the orientation of the
// actual edge, as computed with orient_halfedges.
// will be computed if not provided.
//
// Outputs:
// M: computed mass matrix
// E, oE: these are computed if they are not present, as described above
template <typename DerivedV, typename DerivedF, typename DerivedE,
typename DerivedOE, typename ScalarM>
IGL_INLINE void
cr_vector_mass(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarM>& M);
template <typename DerivedV, typename DerivedF, typename DerivedE,
typename DerivedOE, typename ScalarM>
IGL_INLINE void
cr_vector_mass(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
Eigen::PlainObjectBase<DerivedE>& E,
Eigen::PlainObjectBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarM>& M);
// Version that uses intrinsic quantities as input
//
// Inputs:
// F: input mesh connectivity
// l_sq: squared edge lengths of each halfedge
// dA: double area of each face
// E: a mapping from each halfedge to each edge.
// oE: the orientation of each halfedge compared to the orientation of the
// actual edge.
//
// Outputs:
// M: computed mass matrix
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
typename DerivedOE, typename ScalarM>
IGL_INLINE void
cr_vector_mass_intrinsic(
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarM>& M);
template <typename DerivedF, typename DerivedL_sq, typename DeriveddA,
typename DerivedE, typename DerivedOE, typename ScalarM>
IGL_INLINE void
cr_vector_mass_intrinsic(
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
const Eigen::MatrixBase<DeriveddA>& dA,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarM>& M);
}
#ifndef IGL_STATIC_LIBRARY
# include "cr_vector_mass.cpp"
#endif
#endif
@@ -97,4 +97,5 @@ void igl::crouzeix_raviart_cotmatrix(
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::crouzeix_raviart_cotmatrix<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int>&);
template void igl::crouzeix_raviart_cotmatrix<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
#endif
@@ -82,4 +82,5 @@ void igl::crouzeix_raviart_massmatrix(
template void igl::crouzeix_raviart_massmatrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
template void igl::crouzeix_raviart_massmatrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int>&);
template void igl::crouzeix_raviart_massmatrix<float, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<float, 0, int>&);
template void igl::crouzeix_raviart_massmatrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
#endif
+127
View File
@@ -0,0 +1,127 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "curved_hessian_energy.h"
#include "orient_halfedges.h"
#include "doublearea.h"
#include "squared_edge_lengths.h"
#include "cr_vector_laplacian.h"
#include "cr_vector_mass.h"
#include "cr_vector_curvature_correction.h"
#include "scalar_to_cr_vector_gradient.h"
template <typename DerivedV, typename DerivedF, typename ScalarQ>
IGL_INLINE void
igl::curved_hessian_energy(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
Eigen::SparseMatrix<ScalarQ>& Q)
{
Eigen::MatrixXi E, oE;
curved_hessian_energy(V, F, E, oE, Q);
}
template <typename DerivedV, typename DerivedF, typename DerivedE,
typename DerivedOE, typename ScalarQ>
IGL_INLINE void
igl::curved_hessian_energy(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarQ>& Q)
{
Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic>
l_sq;
squared_edge_lengths(V, F, l_sq);
curved_hessian_energy_intrinsic(F, l_sq, E, oE, Q);
}
template <typename DerivedV, typename DerivedF, typename DerivedE,
typename DerivedOE, typename ScalarQ>
IGL_INLINE void
igl::curved_hessian_energy(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
Eigen::PlainObjectBase<DerivedE>& E,
Eigen::PlainObjectBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarQ>& Q)
{
if(E.rows()!=F.rows() || E.cols()!=F.cols() || oE.rows()!=F.rows() ||
oE.cols()!=F.cols()) {
orient_halfedges(F, E, oE);
}
const Eigen::PlainObjectBase<DerivedE>& cE = E;
const Eigen::PlainObjectBase<DerivedOE>& coE = oE;
curved_hessian_energy(V, F, cE, coE, Q);
}
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
typename DerivedOE, typename ScalarQ>
IGL_INLINE void
igl::curved_hessian_energy_intrinsic(
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarQ>& Q)
{
Eigen::Matrix<typename DerivedL_sq::Scalar, Eigen::Dynamic, Eigen::Dynamic>
dA;
Eigen::Matrix<typename DerivedL_sq::Scalar, Eigen::Dynamic, Eigen::Dynamic>
l_sqrt = l_sq.array().sqrt().matrix();
doublearea(l_sqrt, dA);
curved_hessian_energy_intrinsic(F, l_sq, dA, E, oE, Q);
}
template <typename DerivedF, typename DerivedL_sq, typename DeriveddA,
typename DerivedE, typename DerivedOE, typename ScalarQ>
IGL_INLINE void
igl::curved_hessian_energy_intrinsic(
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
const Eigen::MatrixBase<DeriveddA>& dA,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarQ>& Q)
{
//Matrices that need to be combined
Eigen::SparseMatrix<ScalarQ> M, D, L, K;
cr_vector_mass_intrinsic(F, l_sq, dA, E, oE, M);
scalar_to_cr_vector_gradient_intrinsic(F, l_sq, dA, E, oE, D);
cr_vector_laplacian_intrinsic(F, l_sq, dA, E, oE, L);
cr_vector_curvature_correction_intrinsic(F, l_sq, E, oE, K);
//Invert M
std::vector<Eigen::Triplet<ScalarQ> > tripletListMi;
for(Eigen::Index k=0; k<M.outerSize(); ++k) {
for(typename Eigen::SparseMatrix<ScalarQ>::InnerIterator it(M,k);
it; ++it) {
if(it.value() > 0) {
tripletListMi.emplace_back(it.row(), it.col(), 1./it.value());
}
}
}
Eigen::SparseMatrix<ScalarQ> Mi(M.rows(), M.cols());
Mi.setFromTriplets(tripletListMi.begin(), tripletListMi.end());
//Hessian energy matrix
Q = D.transpose()*Mi*(L + K)*Mi*D;
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template void igl::curved_hessian_energy<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
#endif
+114
View File
@@ -0,0 +1,114 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_CURVED_HESSIAN_ENERGY_H
#define IGL_CURVED_HESSIAN_ENERGY_H
#include "igl_inline.h"
#include <Eigen/Core>
#include <Eigen/Sparse>
namespace igl
{
// Computes the curved Hessian energy using the Crouzeix-Raviart
// discretization.
// See Oded Stein, Alec Jacobson, Max Wardetzky, Eitan Grinspun, 2020.
// "A Smoothness Energy without Boundary Distortion for Curved Surfaces"
//
// Inputs:
// V, F: input mesh
//
// Outputs:
// Q: computed Hessian energy matrix
template <typename DerivedV, typename DerivedF, typename ScalarQ>
IGL_INLINE void
curved_hessian_energy(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
Eigen::SparseMatrix<ScalarQ>& Q);
// Version that exposes the edge orientation used.
//
// Inputs:
// V, F: input mesh
// E: a mapping from each halfedge to each edge, as computed with
// orient_halfedges.
// will be computed if not provided.
// oE: the orientation of each halfedge compared to the orientation of the
// actual edge, as computed with orient_halfedges.
// will be computed if not provided.
//
// Outputs:
// Q: computed Hessian energy matrix
// E, oE: these are computed if they are not present, as described above
template <typename DerivedV, typename DerivedF, typename DerivedE,
typename DerivedOE, typename ScalarQ>
IGL_INLINE void
curved_hessian_energy(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarQ>& Q);
template <typename DerivedV, typename DerivedF, typename DerivedE,
typename DerivedOE, typename ScalarQ>
IGL_INLINE void
curved_hessian_energy(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F,
Eigen::PlainObjectBase<DerivedE>& E,
Eigen::PlainObjectBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarQ>& Q);
// Version that uses intrinsic quantities as input
//
// Inputs:
// F: input mesh connectivity
// l_sq: squared edge lengths of each halfedge
// dA: double area of each face
// E: a mapping from each halfedge to each edge.
// oE: the orientation of each halfedge compared to the orientation of the
// actual edge.
//
// Outputs:
// Q: computed Hessian energy matrix
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
typename DerivedOE, typename ScalarQ>
IGL_INLINE void
curved_hessian_energy_intrinsic(
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarQ>& Q);
template <typename DerivedF, typename DerivedL_sq, typename DeriveddA,
typename DerivedE, typename DerivedOE, typename ScalarQ>
IGL_INLINE void
curved_hessian_energy_intrinsic(
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
const Eigen::MatrixBase<DeriveddA>& dA,
const Eigen::MatrixBase<DerivedE>& E,
const Eigen::MatrixBase<DerivedOE>& oE,
Eigen::SparseMatrix<ScalarQ>& Q);
}
#ifndef IGL_STATIC_LIBRARY
# include "curved_hessian_energy.cpp"
#endif
#endif
+80 -197
View File
@@ -8,11 +8,13 @@
#include "decimate.h"
#include "collapse_edge.h"
#include "edge_flaps.h"
#include "decimate_trivial_callbacks.h"
#include "is_edge_manifold.h"
#include "remove_unreferenced.h"
#include "slice_mask.h"
#include "slice.h"
#include "connect_boundary_to_infinity.h"
#include "parallel_for.h"
#include "max_faces_stopping_condition.h"
#include "shortest_edge_and_midpoint.h"
@@ -34,18 +36,34 @@ IGL_INLINE bool igl::decimate(
DerivedV VO;
DerivedF FO;
igl::connect_boundary_to_infinity(V,F,VO,FO);
Eigen::VectorXi EMAP;
Eigen::MatrixXi E,EF,EI;
edge_flaps(FO,E,EMAP,EF,EI);
// decimate will not work correctly on non-edge-manifold meshes. By extension
// this includes meshes with non-manifold vertices on the boundary since these
// will create a non-manifold edge when connected to infinity.
if(!is_edge_manifold(FO))
{
return false;
Eigen::Array<bool,Eigen::Dynamic,Eigen::Dynamic> BF;
Eigen::Array<bool,Eigen::Dynamic,1> BE;
if(!is_edge_manifold(FO,E.rows(),EMAP,BF,BE))
{
return false;
}
}
decimate_pre_collapse_callback always_try;
decimate_post_collapse_callback never_care;
decimate_trivial_callbacks(always_try,never_care);
bool ret = decimate(
VO,
FO,
shortest_edge_and_midpoint,
max_faces_stopping_condition(m,orig_m,max_m),
always_try,
never_care,
E,
EMAP,
EF,
EI,
U,
G,
J,
@@ -74,66 +92,17 @@ IGL_INLINE bool igl::decimate(
IGL_INLINE bool igl::decimate(
const Eigen::MatrixXd & OV,
const Eigen::MatrixXi & OF,
const std::function<void(
const int,
const Eigen::MatrixXd &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
const Eigen::VectorXi &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
double &,
Eigen::RowVectorXd &)> & cost_and_placement,
const std::function<bool(
const Eigen::MatrixXd &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
const Eigen::VectorXi &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
const std::set<std::pair<double,int> > &,
const std::vector<std::set<std::pair<double,int> >::iterator > &,
const Eigen::MatrixXd &,
const int,
const int,
const int,
const int,
const int)> & stopping_condition,
const decimate_cost_and_placement_callback & cost_and_placement,
const decimate_stopping_condition_callback & stopping_condition,
Eigen::MatrixXd & U,
Eigen::MatrixXi & G,
Eigen::VectorXi & J,
Eigen::VectorXi & I
)
{
const auto always_try = [](
const Eigen::MatrixXd & ,/*V*/
const Eigen::MatrixXi & ,/*F*/
const Eigen::MatrixXi & ,/*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & ,/*EF*/
const Eigen::MatrixXi & ,/*EI*/
const std::set<std::pair<double,int> > & ,/*Q*/
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
const Eigen::MatrixXd & ,/*C*/
const int /*e*/
) -> bool { return true;};
const auto never_care = [](
const Eigen::MatrixXd & , /*V*/
const Eigen::MatrixXi & , /*F*/
const Eigen::MatrixXi & , /*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & , /*EF*/
const Eigen::MatrixXi & , /*EI*/
const std::set<std::pair<double,int> > & , /*Q*/
const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
const Eigen::MatrixXd & , /*C*/
const int , /*e*/
const int , /*e1*/
const int , /*e2*/
const int , /*f1*/
const int , /*f2*/
const bool /*collapsed*/
)-> void { };
decimate_pre_collapse_callback always_try;
decimate_post_collapse_callback never_care;
decimate_trivial_callbacks(always_try,never_care);
return igl::decimate(
OV,OF,cost_and_placement,stopping_condition,always_try,never_care,U,G,J,I);
}
@@ -141,70 +110,18 @@ IGL_INLINE bool igl::decimate(
IGL_INLINE bool igl::decimate(
const Eigen::MatrixXd & OV,
const Eigen::MatrixXi & OF,
const std::function<void(
const int,
const Eigen::MatrixXd &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
const Eigen::VectorXi &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
double &,
Eigen::RowVectorXd &)> & cost_and_placement,
const std::function<bool(
const Eigen::MatrixXd &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
const Eigen::VectorXi &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
const std::set<std::pair<double,int> > &,
const std::vector<std::set<std::pair<double,int> >::iterator > &,
const Eigen::MatrixXd &,
const int,
const int,
const int,
const int,
const int)> & stopping_condition,
const std::function<bool(
const Eigen::MatrixXd & ,/*V*/
const Eigen::MatrixXi & ,/*F*/
const Eigen::MatrixXi & ,/*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & ,/*EF*/
const Eigen::MatrixXi & ,/*EI*/
const std::set<std::pair<double,int> > & ,/*Q*/
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
const Eigen::MatrixXd & ,/*C*/
const int /*e*/
)> & pre_collapse,
const std::function<void(
const Eigen::MatrixXd & , /*V*/
const Eigen::MatrixXi & , /*F*/
const Eigen::MatrixXi & , /*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & , /*EF*/
const Eigen::MatrixXi & , /*EI*/
const std::set<std::pair<double,int> > & , /*Q*/
const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
const Eigen::MatrixXd & , /*C*/
const int , /*e*/
const int , /*e1*/
const int , /*e2*/
const int , /*f1*/
const int , /*f2*/
const bool /*collapsed*/
)> & post_collapse,
const decimate_cost_and_placement_callback & cost_and_placement,
const decimate_stopping_condition_callback & stopping_condition,
const decimate_pre_collapse_callback & pre_collapse,
const decimate_post_collapse_callback & post_collapse,
Eigen::MatrixXd & U,
Eigen::MatrixXi & G,
Eigen::VectorXi & J,
Eigen::VectorXi & I
)
{
using namespace Eigen;
using namespace std;
VectorXi EMAP;
MatrixXi E,EF,EI;
Eigen::VectorXi EMAP;
Eigen::MatrixXi E,EF,EI;
edge_flaps(OF,E,EMAP,EF,EI);
return igl::decimate(
OV,OF,
@@ -213,64 +130,13 @@ IGL_INLINE bool igl::decimate(
U,G,J,I);
}
IGL_INLINE bool igl::decimate(
const Eigen::MatrixXd & OV,
const Eigen::MatrixXi & OF,
const std::function<void(
const int,
const Eigen::MatrixXd &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
const Eigen::VectorXi &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
double &,
Eigen::RowVectorXd &)> & cost_and_placement,
const std::function<bool(
const Eigen::MatrixXd &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
const Eigen::VectorXi &,
const Eigen::MatrixXi &,
const Eigen::MatrixXi &,
const std::set<std::pair<double,int> > &,
const std::vector<std::set<std::pair<double,int> >::iterator > &,
const Eigen::MatrixXd &,
const int,
const int,
const int,
const int,
const int)> & stopping_condition,
const std::function<bool(
const Eigen::MatrixXd & ,/*V*/
const Eigen::MatrixXi & ,/*F*/
const Eigen::MatrixXi & ,/*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & ,/*EF*/
const Eigen::MatrixXi & ,/*EI*/
const std::set<std::pair<double,int> > & ,/*Q*/
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
const Eigen::MatrixXd & ,/*C*/
const int /*e*/
)> & pre_collapse,
const std::function<void(
const Eigen::MatrixXd & , /*V*/
const Eigen::MatrixXi & , /*F*/
const Eigen::MatrixXi & , /*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & , /*EF*/
const Eigen::MatrixXi & , /*EI*/
const std::set<std::pair<double,int> > & , /*Q*/
const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
const Eigen::MatrixXd & , /*C*/
const int , /*e*/
const int , /*e1*/
const int , /*e2*/
const int , /*f1*/
const int , /*f2*/
const bool /*collapsed*/
)> & post_collapse,
const decimate_cost_and_placement_callback & cost_and_placement,
const decimate_stopping_condition_callback & stopping_condition,
const decimate_pre_collapse_callback & pre_collapse,
const decimate_post_collapse_callback & post_collapse,
const Eigen::MatrixXi & OE,
const Eigen::VectorXi & OEMAP,
const Eigen::MatrixXi & OEF,
@@ -281,57 +147,74 @@ IGL_INLINE bool igl::decimate(
Eigen::VectorXi & I
)
{
// Decimate 1
using namespace Eigen;
using namespace std;
// Working copies
Eigen::MatrixXd V = OV;
Eigen::MatrixXi F = OF;
Eigen::MatrixXi E = OE;
Eigen::VectorXi EMAP = OEMAP;
Eigen::MatrixXi EF = OEF;
Eigen::MatrixXi EI = OEI;
typedef std::set<std::pair<double,int> > PriorityQueue;
PriorityQueue Q;
std::vector<PriorityQueue::iterator > Qit;
Qit.resize(E.rows());
VectorXi EMAP;
MatrixXi E,EF,EI;
edge_flaps(F,E,EMAP,EF,EI);
{
Eigen::Array<bool,Eigen::Dynamic,Eigen::Dynamic> BF;
Eigen::Array<bool,Eigen::Dynamic,1> BE;
if(!is_edge_manifold(F,E.rows(),EMAP,BF,BE))
{
return false;
}
}
igl::min_heap<std::tuple<double,int,int> > Q;
// Could reserve with https://stackoverflow.com/a/29236236/148668
Eigen::VectorXi EQ = Eigen::VectorXi::Zero(E.rows());
// If an edge were collapsed, we'd collapse it to these points:
MatrixXd C(E.rows(),V.cols());
for(int e = 0;e<E.rows();e++)
// Pushing into a vector then using constructor was slower. Maybe using
// std::move + make_heap would squeeze out something?
// Separating the cost/placement evaluation from the Q filling is a
// performance hit for serial but faster if we can parallelize the
// cost/placement.
{
double cost = e;
RowVectorXd p(1,3);
cost_and_placement(e,V,F,E,EMAP,EF,EI,cost,p);
C.row(e) = p;
Qit[e] = Q.insert(std::pair<double,int>(cost,e)).first;
Eigen::VectorXd costs(E.rows());
igl::parallel_for(E.rows(),[&](const int e)
{
double cost = e;
RowVectorXd p(1,3);
cost_and_placement(e,V,F,E,EMAP,EF,EI,cost,p);
C.row(e) = p;
costs(e) = cost;
},10000);
for(int e = 0;e<E.rows();e++)
{
Q.emplace(costs(e),e,0);
}
}
int prev_e = -1;
bool clean_finish = false;
while(true)
{
if(Q.empty())
{
break;
}
if(Q.begin()->first == std::numeric_limits<double>::infinity())
{
// min cost edge is infinite cost
break;
}
int e,e1,e2,f1,f2;
if(collapse_edge(
cost_and_placement, pre_collapse, post_collapse,
V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2))
cost_and_placement, pre_collapse, post_collapse,
V,F,E,EMAP,EF,EI,Q,EQ,C,e,e1,e2,f1,f2))
{
if(stopping_condition(V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2))
if(stopping_condition(V,F,E,EMAP,EF,EI,Q,EQ,C,e,e1,e2,f1,f2))
{
clean_finish = true;
break;
}
}else
{
if(e == -1)
{
// a candidate edge was not even found in Q.
break;
}
if(prev_e == e)
{
assert(false && "Edge collapse no progress... bad stopping condition?");
@@ -361,6 +244,6 @@ IGL_INLINE bool igl::decimate(
F2.conservativeResize(m,F2.cols());
J.conservativeResize(m);
VectorXi _1;
remove_unreferenced(V,F2,U,G,_1,I);
igl::remove_unreferenced(V,F2,U,G,_1,I);
return clean_finish;
}
+11 -144
View File
@@ -8,9 +8,8 @@
#ifndef IGL_DECIMATE_H
#define IGL_DECIMATE_H
#include "igl_inline.h"
#include "decimate_callback_types.h"
#include <Eigen/Core>
#include <vector>
#include <set>
namespace igl
{
// Assumes (V,F) is a manifold mesh (possibly with boundary) Collapses edges
@@ -68,38 +67,12 @@ namespace igl
IGL_INLINE bool decimate(
const Eigen::MatrixXd & V,
const Eigen::MatrixXi & F,
const std::function<void(
const int /*e*/,
const Eigen::MatrixXd &/*V*/,
const Eigen::MatrixXi &/*F*/,
const Eigen::MatrixXi &/*E*/,
const Eigen::VectorXi &/*EMAP*/,
const Eigen::MatrixXi &/*EF*/,
const Eigen::MatrixXi &/*EI*/,
double & /*cost*/,
Eigen::RowVectorXd & /*p*/
)> & cost_and_placement,
const std::function<bool(
const Eigen::MatrixXd & ,/*V*/
const Eigen::MatrixXi & ,/*F*/
const Eigen::MatrixXi & ,/*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & ,/*EF*/
const Eigen::MatrixXi & ,/*EI*/
const std::set<std::pair<double,int> > & ,/*Q*/
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
const Eigen::MatrixXd & ,/*C*/
const int ,/*e*/
const int ,/*e1*/
const int ,/*e2*/
const int ,/*f1*/
const int /*f2*/
)> & stopping_condition,
const decimate_cost_and_placement_callback & cost_and_placement,
const decimate_stopping_condition_callback & stopping_condition,
Eigen::MatrixXd & U,
Eigen::MatrixXi & G,
Eigen::VectorXi & J,
Eigen::VectorXi & I);
// Inputs:
// pre_collapse callback called with index of edge whose collapse is about
// to be attempted (see collapse_edge)
@@ -109,67 +82,14 @@ namespace igl
IGL_INLINE bool decimate(
const Eigen::MatrixXd & V,
const Eigen::MatrixXi & F,
const std::function<void(
const int /*e*/,
const Eigen::MatrixXd &/*V*/,
const Eigen::MatrixXi &/*F*/,
const Eigen::MatrixXi &/*E*/,
const Eigen::VectorXi &/*EMAP*/,
const Eigen::MatrixXi &/*EF*/,
const Eigen::MatrixXi &/*EI*/,
double & /*cost*/,
Eigen::RowVectorXd & /*p*/
)> & cost_and_placement,
const std::function<bool(
const Eigen::MatrixXd & ,/*V*/
const Eigen::MatrixXi & ,/*F*/
const Eigen::MatrixXi & ,/*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & ,/*EF*/
const Eigen::MatrixXi & ,/*EI*/
const std::set<std::pair<double,int> > & ,/*Q*/
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
const Eigen::MatrixXd & ,/*C*/
const int ,/*e*/
const int ,/*e1*/
const int ,/*e2*/
const int ,/*f1*/
const int /*f2*/
)> & stopping_condition,
const std::function<bool(
const Eigen::MatrixXd & ,/*V*/
const Eigen::MatrixXi & ,/*F*/
const Eigen::MatrixXi & ,/*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & ,/*EF*/
const Eigen::MatrixXi & ,/*EI*/
const std::set<std::pair<double,int> > & ,/*Q*/
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
const Eigen::MatrixXd & ,/*C*/
const int /*e*/
)> & pre_collapse,
const std::function<void(
const Eigen::MatrixXd & , /*V*/
const Eigen::MatrixXi & , /*F*/
const Eigen::MatrixXi & , /*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & , /*EF*/
const Eigen::MatrixXi & , /*EI*/
const std::set<std::pair<double,int> > & , /*Q*/
const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
const Eigen::MatrixXd & , /*C*/
const int , /*e*/
const int , /*e1*/
const int , /*e2*/
const int , /*f1*/
const int , /*f2*/
const bool /*collapsed*/
)> & post_collapse,
const decimate_cost_and_placement_callback & cost_and_placement,
const decimate_stopping_condition_callback & stopping_condition,
const decimate_pre_collapse_callback & pre_collapse,
const decimate_post_collapse_callback & post_collapse,
Eigen::MatrixXd & U,
Eigen::MatrixXi & G,
Eigen::VectorXi & J,
Eigen::VectorXi & I);
// Inputs:
// EMAP #F*3 list of indices into E, mapping each directed edge to unique
// unique edge in E
@@ -177,66 +97,13 @@ namespace igl
// F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1) "
// e=(j->i)
// EI #E by 2 list of edge flap corners (see above).
IGL_INLINE bool decimate(
const Eigen::MatrixXd & V,
const Eigen::MatrixXi & F,
const std::function<void(
const int /*e*/,
const Eigen::MatrixXd &/*V*/,
const Eigen::MatrixXi &/*F*/,
const Eigen::MatrixXi &/*E*/,
const Eigen::VectorXi &/*EMAP*/,
const Eigen::MatrixXi &/*EF*/,
const Eigen::MatrixXi &/*EI*/,
double & /*cost*/,
Eigen::RowVectorXd & /*p*/
)> & cost_and_placement,
const std::function<bool(
const Eigen::MatrixXd & ,/*V*/
const Eigen::MatrixXi & ,/*F*/
const Eigen::MatrixXi & ,/*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & ,/*EF*/
const Eigen::MatrixXi & ,/*EI*/
const std::set<std::pair<double,int> > & ,/*Q*/
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
const Eigen::MatrixXd & ,/*C*/
const int ,/*e*/
const int ,/*e1*/
const int ,/*e2*/
const int ,/*f1*/
const int /*f2*/
)> & stopping_condition,
const std::function<bool(
const Eigen::MatrixXd & ,/*V*/
const Eigen::MatrixXi & ,/*F*/
const Eigen::MatrixXi & ,/*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & ,/*EF*/
const Eigen::MatrixXi & ,/*EI*/
const std::set<std::pair<double,int> > & ,/*Q*/
const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
const Eigen::MatrixXd & ,/*C*/
const int /*e*/
)> & pre_collapse,
const std::function<void(
const Eigen::MatrixXd & , /*V*/
const Eigen::MatrixXi & , /*F*/
const Eigen::MatrixXi & , /*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & , /*EF*/
const Eigen::MatrixXi & , /*EI*/
const std::set<std::pair<double,int> > & , /*Q*/
const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
const Eigen::MatrixXd & , /*C*/
const int , /*e*/
const int , /*e1*/
const int , /*e2*/
const int , /*f1*/
const int , /*f2*/
const bool /*collapsed*/
)> & post_collapse,
const decimate_cost_and_placement_callback & cost_and_placement,
const decimate_stopping_condition_callback & stopping_condition,
const decimate_pre_collapse_callback & pre_collapse,
const decimate_post_collapse_callback & post_collapse,
const Eigen::MatrixXi & E,
const Eigen::VectorXi & EMAP,
const Eigen::MatrixXi & EF,
+76
View File
@@ -0,0 +1,76 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_DECIMATE_CALLBACK_TYPES_H
#define IGL_DECIMATE_CALLBACK_TYPES_H
#include <Eigen/Core>
#include "min_heap.h"
namespace igl
{
// Function handles used to customize the `igl::decimate` command.
using decimate_cost_and_placement_callback =
std::function<void(
const int ,/*e*/
const Eigen::MatrixXd & ,/*V*/
const Eigen::MatrixXi & ,/*F*/
const Eigen::MatrixXi & ,/*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & ,/*EF*/
const Eigen::MatrixXi & ,/*EI*/
double & ,/*cost*/
Eigen::RowVectorXd & /*p*/
)>;
using decimate_stopping_condition_callback =
std::function<bool(
const Eigen::MatrixXd & ,/*V*/
const Eigen::MatrixXi & ,/*F*/
const Eigen::MatrixXi & ,/*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & ,/*EF*/
const Eigen::MatrixXi & ,/*EI*/
const igl::min_heap< std::tuple<double,int,int> > & ,/*Q*/
const Eigen::VectorXi & ,/*EQ*/
const Eigen::MatrixXd & ,/*C*/
const int ,/*e*/
const int ,/*e1*/
const int ,/*e2*/
const int ,/*f1*/
const int /*f2*/
)>;
using decimate_pre_collapse_callback =
std::function<bool(
const Eigen::MatrixXd & ,/*V*/
const Eigen::MatrixXi & ,/*F*/
const Eigen::MatrixXi & ,/*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & ,/*EF*/
const Eigen::MatrixXi & ,/*EI*/
const igl::min_heap< std::tuple<double,int,int> > & ,/*Q*/
const Eigen::VectorXi & ,/*EQ*/
const Eigen::MatrixXd & ,/*C*/
const int /*e*/
)>;
using decimate_post_collapse_callback =
std::function<void(
const Eigen::MatrixXd & ,/*V*/
const Eigen::MatrixXi & ,/*F*/
const Eigen::MatrixXi & ,/*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & ,/*EF*/
const Eigen::MatrixXi & ,/*EI*/
const igl::min_heap< std::tuple<double,int,int> > & ,/*Q*/
const Eigen::VectorXi & ,/*EQ*/
const Eigen::MatrixXd & ,/*C*/
const int ,/*e*/
const int ,/*e1*/
const int ,/*e2*/
const int ,/*f1*/
const int ,/*f2*/
const bool /*collapsed*/
)>;
}
#endif
@@ -0,0 +1,43 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "decimate_trivial_callbacks.h"
IGL_INLINE void igl::decimate_trivial_callbacks(
decimate_pre_collapse_callback & always_try,
decimate_post_collapse_callback & never_care)
{
always_try = [](
const Eigen::MatrixXd & ,/*V*/
const Eigen::MatrixXi & ,/*F*/
const Eigen::MatrixXi & ,/*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & ,/*EF*/
const Eigen::MatrixXi & ,/*EI*/
const igl::min_heap< std::tuple<double,int,int> > & ,/*Q*/
const Eigen::VectorXi & ,/*EQ*/
const Eigen::MatrixXd & ,/*C*/
const int /*e*/
) -> bool { return true;};
never_care = [](
const Eigen::MatrixXd & ,/*V*/
const Eigen::MatrixXi & ,/*F*/
const Eigen::MatrixXi & ,/*E*/
const Eigen::VectorXi & ,/*EMAP*/
const Eigen::MatrixXi & ,/*EF*/
const Eigen::MatrixXi & ,/*EI*/
const igl::min_heap< std::tuple<double,int,int> > & ,/*Q*/
const Eigen::VectorXi & ,/*EQ*/
const Eigen::MatrixXd & ,/*C*/
const int ,/*e*/
const int ,/*e1*/
const int ,/*e2*/
const int ,/*f1*/
const int ,/*f2*/
const bool /*collapsed*/
)-> void { };
}
+31
View File
@@ -0,0 +1,31 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_DECIMATE_TRIVIAL_CALLBACKS_H
#define IGL_DECIMATE_TRIVIAL_CALLBACKS_H
#include "igl_inline.h"
#include "decimate_callback_types.h"
namespace igl
{
// Function to build trivial pre and post collapse actions.
//
// Outputs:
// always_try function that always returns true (always attempt the next
// edge collapse)
// never_care fuction that is always a no-op (never have a post collapse
// response)
IGL_INLINE void decimate_trivial_callbacks(
decimate_pre_collapse_callback & always_try,
decimate_post_collapse_callback & never_care);
};
#ifndef IGL_STATIC_LIBRARY
# include "decimate_trivial_callbacks.cpp"
#endif
#endif
+3 -2
View File
@@ -1,7 +1,7 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
//
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
@@ -17,7 +17,7 @@ IGL_INLINE int igl::dijkstra(
Eigen::PlainObjectBase<DerivedP> &previous)
{
int numV = VV.size();
min_distance.setConstant(numV, 1, std::numeric_limits<typename DerivedD::Scalar>::infinity());
min_distance.setConstant(numV, 1, std::numeric_limits<typename DerivedD::Scalar>::max());
min_distance[source] = 0;
previous.setConstant(numV, 1, -1);
std::set<std::pair<typename DerivedD::Scalar, IndexType> > vertex_queue;
@@ -132,6 +132,7 @@ IGL_INLINE int igl::dijkstra(
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template int igl::dijkstra<int, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(int const&, std::set<int, std::less<int>, std::allocator<int> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
template int igl::dijkstra<int, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(int const&, std::set<int, std::less<int>, std::allocator<int> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
template void igl::dijkstra<int, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(int const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::vector<int, std::allocator<int> >&);
template int igl::dijkstra<int, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, int const&, std::set<int, std::less<int>, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
#endif
+268
View File
@@ -0,0 +1,268 @@
// This file is part of libigl, a simple C++ geometry processing library.
//
// Copyright (C) 2020 Xiangyu Kong <xiangyu.kong@mail.utoronto.ca>
//
// This Source Code Form is subject to 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 "direct_delta_mush.h"
#include "cotmatrix.h"
template <
typename DerivedV,
typename DerivedOmega,
typename DerivedU>
IGL_INLINE void igl::direct_delta_mush(
const Eigen::MatrixBase<DerivedV> & V,
const std::vector<Eigen::Affine3d, Eigen::aligned_allocator<Eigen::Affine3d> > & T,
const Eigen::MatrixBase<DerivedOmega> & Omega,
Eigen::PlainObjectBase<DerivedU> & U)
{
using namespace Eigen;
// Shape checks
assert(V.cols() == 3 && "V should contain 3D positions.");
assert(Omega.rows() == V.rows() && "Omega contain the same number of rows as V.");
assert(Omega.cols() == T.size() * 10 && "Omega should have #T*10 columns.");
typedef typename DerivedV::Scalar Scalar;
int n = V.rows();
int m = T.size();
// V_homogeneous: #V by 4, homogeneous version of V
// Note:
// In the paper, the rest pose vertices are represented in U \in R^{4 x #V}
// Thus the formulae involving U would differ from the paper by a transpose.
Matrix<Scalar, Dynamic, 4> V_homogeneous(n, 4);
V_homogeneous << V, Matrix<Scalar, Dynamic, 1>::Ones(n, 1);
U.resize(n, 3);
for (int i = 0; i < n; ++i)
{
// Construct Q matrix using Omega and Transformations
Matrix<Scalar, 4, 4> Q_mat(4, 4);
Q_mat = Matrix<Scalar, 4, 4>::Zero(4, 4);
for (int j = 0; j < m; ++j)
{
Matrix<typename DerivedOmega::Scalar, 4, 4> Omega_curr(4, 4);
Matrix<typename DerivedOmega::Scalar, 10, 1> curr = Omega.block(i, j * 10, 1, 10).transpose();
Omega_curr << curr(0), curr(1), curr(2), curr(3),
curr(1), curr(4), curr(5), curr(6),
curr(2), curr(5), curr(7), curr(8),
curr(3), curr(6), curr(8), curr(9);
Affine3d M_curr = T[j];
Q_mat += M_curr.matrix() * Omega_curr;
}
// Normalize so that the last element is 1
Q_mat /= Q_mat(Q_mat.rows() - 1, Q_mat.cols() - 1);
Matrix<Scalar, 3, 3> Q_i = Q_mat.block(0, 0, 3, 3);
Matrix<Scalar, 3, 1> q_i = Q_mat.block(0, 3, 3, 1);
Matrix<Scalar, 3, 1> p_i = Q_mat.block(3, 0, 1, 3).transpose();
// Get rotation and translation matrices using SVD
Matrix<Scalar, 3, 3> SVD_i = Q_i - q_i * p_i.transpose();
JacobiSVD<Matrix<Scalar, 3, 3>> svd;
svd.compute(SVD_i, ComputeFullU | ComputeFullV);
Matrix<Scalar, 3, 3> R_i = svd.matrixU() * svd.matrixV().transpose();
Matrix<Scalar, 3, 1> t_i = q_i - R_i * p_i;
// Gamma final transformation matrix
Matrix<Scalar, 3, 4> Gamma_i(3, 4);
Gamma_i.block(0, 0, 3, 3) = R_i;
Gamma_i.block(0, 3, 3, 1) = t_i;
// Final deformed position
Matrix<Scalar, 4, 1> v_i = V_homogeneous.row(i);
U.row(i) = Gamma_i * v_i;
}
}
template <
typename DerivedV,
typename DerivedF,
typename DerivedW,
typename DerivedOmega>
IGL_INLINE void igl::direct_delta_mush_precomputation(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F,
const Eigen::MatrixBase<DerivedW> & W,
const int p,
const typename DerivedV::Scalar lambda,
const typename DerivedV::Scalar kappa,
const typename DerivedV::Scalar alpha,
Eigen::PlainObjectBase<DerivedOmega> & Omega)
{
using namespace Eigen;
// Shape checks
assert(V.cols() == 3 && "V should contain 3D positions.");
assert(F.cols() == 3 && "F should contain triangles.");
assert(W.rows() == V.rows() && "W.rows() should be equal to V.rows().");
// Parameter checks
assert(p > 0 && "Laplacian iteration p should be positive.");
assert(lambda > 0 && "lambda should be positive.");
assert(kappa > 0 && kappa < lambda && "kappa should be positive and less than lambda.");
assert(alpha >= 0 && alpha < 1 && "alpha should be non-negative and less than 1.");
typedef typename DerivedV::Scalar Scalar;
// lambda helper
// Given a square matrix, extract the upper triangle (including diagonal) to an array.
// E.g. 1 2 3 4
// 5 6 7 8 -> [1, 2, 3, 4, 6, 7, 8, 11, 12, 16]
// 9 10 11 12 0 1 2 3 4 5 6 7 8 9
// 13 14 15 16
auto extract_upper_triangle = [](
const Matrix<Scalar, Dynamic, Dynamic> & full) -> Matrix<Scalar, Dynamic, 1>
{
int dims = full.rows();
Matrix<Scalar, Dynamic, 1> upper_triangle((dims * (dims + 1)) / 2);
int vector_idx = 0;
for (int i = 0; i < dims; ++i)
{
for (int j = i; j < dims; ++j)
{
upper_triangle(vector_idx) = full(i, j);
vector_idx++;
}
}
return upper_triangle;
};
const int n = V.rows();
const int m = W.cols();
// V_homogeneous: #V by 4, homogeneous version of V
// Note:
// in the paper, the rest pose vertices are represented in U \in R^{4 \times #V}
// Thus the formulae involving U would differ from the paper by a transpose.
Matrix<Scalar, Dynamic, 4> V_homogeneous(n, 4);
V_homogeneous << V, Matrix<Scalar, Dynamic, 1>::Ones(n);
// Identity matrix of #V by #V
SparseMatrix<Scalar> I(n, n);
I.setIdentity();
// Laplacian matrix of #V by #V
// L_bar = L \times D_L^{-1}
SparseMatrix<Scalar> L;
igl::cotmatrix(V, F, L);
L = -L;
// Inverse of diagonal matrix = reciprocal elements in diagonal
Matrix<Scalar, Dynamic, 1> D_L = L.diagonal();
// D_L = D_L.array().pow(-1); // Not using this since not sure if diagonal contains 0
for (int i = 0; i < D_L.size(); ++i)
{
if (D_L(i) != 0)
{
D_L(i) = 1 / D_L(i);
}
}
SparseMatrix<Scalar> D_L_inv = D_L.asDiagonal().toDenseMatrix().sparseView();
SparseMatrix<Scalar> L_bar = L * D_L_inv;
// Implicitly and iteratively solve for W'
// w'_{ij} = \sum_{k=1}^{n}{C_{ki} w_{kj}} where C = (I + kappa L_bar)^{-p}:
// W' = C^T \times W => c^T W_k = W_{k-1} where c = (I + kappa L_bar)
// C positive semi-definite => ldlt solver
SimplicialLDLT<SparseMatrix<Scalar>> ldlt_W_prime;
SparseMatrix<Scalar> c(I + kappa * L_bar);
// working copy
DerivedW W_prime(W);
ldlt_W_prime.compute(c.transpose());
for (int iter = 0; iter < p; ++iter)
{
W_prime = ldlt_W_prime.solve(W_prime);
}
// U_precomputed: #V by 10
// Cache u_i^T \dot u_i \in R^{4 x 4} to reduce computation time.
Matrix<Scalar, Dynamic, 10> U_precomputed(n, 10);
for (int k = 0; k < n; ++k)
{
Matrix<Scalar, 4, 4> u_full = V_homogeneous.row(k).transpose() * V_homogeneous.row(k);
U_precomputed.row(k) = extract_upper_triangle(u_full);
}
// U_prime: #V by #T*10 of u_{jx}
// Each column of U_prime (u_{jx}) is the element-wise product of
// W_j and U_precomputed_x where j \in {1...m}, x \in {1...10}
Matrix<Scalar, Dynamic, Dynamic> U_prime(n, m * 10);
for (int j = 0; j < m; ++j)
{
Matrix<Scalar, Dynamic, 1> w_j = W.col(j);
for (int x = 0; x < 10; ++x)
{
Matrix<Scalar, Dynamic, 1> u_x = U_precomputed.col(x);
U_prime.col(10 * j + x) = w_j.array() * u_x.array();
}
}
// Implicitly and iteratively solve for Psi: #V by #T*10 of \Psi_{ij}s.
// Note: Using dense matrices to solve for Psi will cause the program to hang.
// The following won't work
// Matrix<Scalar, Dynamic, Dynamic> Psi(U_prime);
// Matrix<Scalar, Dynamic, Dynamic> b((I + lambda * L_bar).transpose());
// for (int iter = 0; iter < p; ++iter)
// {
// Psi = b.ldlt().solve(Psi); // hangs here
// }
// Convert to sparse matrices and compute
Matrix<Scalar, Dynamic, Dynamic> Psi = U_prime.sparseView();
SparseMatrix<Scalar> b = (I + lambda * L_bar).transpose();
SimplicialLDLT<SparseMatrix<Scalar>> ldlt_Psi;
ldlt_Psi.compute(b);
for (int iter = 0; iter < p; ++iter)
{
Psi = ldlt_Psi.solve(Psi);
}
// P: #V by 10 precomputed upper triangle of
// p_i p_i^T , p_i
// p_i^T , 1
// where p_i = (\sum_{j=1}^{n} Psi_{ij})'s top right 3 by 1 column
Matrix<Scalar, Dynamic, 10> P(n, 10);
for (int i = 0; i < n; ++i)
{
Matrix<Scalar, 3, 1> p_i = Matrix<Scalar, 3, 1>::Zero(3);
Scalar last = 0;
for (int j = 0; j < m; ++j)
{
Matrix<Scalar, 3, 1> p_i_curr(3);
p_i_curr << Psi(i, j * 10 + 3), Psi(i, j * 10 + 6), Psi(i, j * 10 + 8);
p_i += p_i_curr;
last += Psi(i, j * 10 + 9);
}
p_i /= last; // normalize
Matrix<Scalar, 4, 4> p_matrix(4, 4);
p_matrix.block(0, 0, 3, 3) = p_i * p_i.transpose();
p_matrix.block(0, 3, 3, 1) = p_i;
p_matrix.block(3, 0, 1, 3) = p_i.transpose();
p_matrix(3, 3) = 1;
P.row(i) = extract_upper_triangle(p_matrix);
}
// Omega
Omega.resize(n, m * 10);
for (int i = 0; i < n; ++i)
{
Matrix<Scalar, 10, 1> p_vector = P.row(i);
for (int j = 0; j < m; ++j)
{
Matrix<Scalar, 10, 1> Omega_curr(10);
Matrix<Scalar, 10, 1> Psi_curr = Psi.block(i, j * 10, 1, 10).transpose();
Omega_curr = (1. - alpha) * Psi_curr + alpha * W_prime(i, j) * p_vector;
Omega.block(i, j * 10, 1, 10) = Omega_curr.transpose();
}
}
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template void igl::direct_delta_mush<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&, std::vector<Eigen::Transform<double, 3, 2, 0>, Eigen::aligned_allocator<Eigen::Transform<double, 3, 2, 0> > > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&); template void igl::direct_delta_mush_precomputation<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::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&, int, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
#endif
+72
View File
@@ -0,0 +1,72 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Xiangyu Kong <xiangyu.kong@mail.utoronto.ca>
//
// This Source Code Form is subject to 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_DIRECT_DELTA_MUSH_H
#define IGL_DIRECT_DELTA_MUSH_H
#include "igl_inline.h"
#include <Eigen/Core>
#include <Eigen/Sparse>
#include <Eigen/Geometry>
#include <vector>
namespace igl {
// Computes Direct Delta Mesh Skinning (Variant 0) from "Direct Delta Mush
// Skinning and Variants"
//
// Inputs:
// V #V by 3 list of rest pose vertex positions
// T #T list of bone pose transformations
// Omega #V by #T*10 list of precomputated matrix values
// Outputs:
// U #V by 3 list of output vertex positions
template <
typename DerivedV,
typename DerivedOmega,
typename DerivedU>
IGL_INLINE void direct_delta_mush(
const Eigen::MatrixBase<DerivedV> & V,
const std::vector<
Eigen::Affine3d, Eigen::aligned_allocator<Eigen::Affine3d>
> & T, /* should eventually be templated more generally than double */
const Eigen::MatrixBase<DerivedOmega> & Omega,
Eigen::PlainObjectBase<DerivedU> & U);
// Precomputation
//
// Inputs:
// V #V by 3 list of rest pose vertex positions
// F #F by 3 list of triangle indices into rows of V
// W #V by #Edges list of weights
// p number of smoothing iterations
// lambda rotation smoothing step size
// kappa translation smoothness step size
// alpha translation smoothness blending weight
// Outputs:
// Omega #V by #T*10 list of precomputated matrix values
template <
typename DerivedV,
typename DerivedF,
typename DerivedW,
typename DerivedOmega>
IGL_INLINE void direct_delta_mush_precomputation(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F,
const Eigen::MatrixBase<DerivedW> & W,
const int p,
const typename DerivedV::Scalar lambda,
const typename DerivedV::Scalar kappa,
const typename DerivedV::Scalar alpha,
Eigen::PlainObjectBase<DerivedOmega> & Omega);
} // namespace igl
#ifndef IGL_STATIC_LIBRARY
# include "direct_delta_mush.cpp"
#endif
#endif
+38
View File
@@ -84,3 +84,41 @@ IGL_INLINE bool igl::edge_collapse_is_valid(
}
return true;
}
IGL_INLINE bool igl::edge_collapse_is_valid(
std::vector<int> & Nsv,
std::vector<int> & Ndv)
{
// Do we really need to check if edge is IGL_COLLAPSE_EDGE_NULL ?
if(Nsv.size()<2 || Ndv.size()<2)
{
// Bogus data
assert(false);
return false;
}
// determine if the first two vertices are the same before reordering.
// If they are and there are 3 each, then (I claim) this is an edge on a
// single tet.
const bool first_two_same = (Nsv[0] == Ndv[0]) && (Nsv[1] == Ndv[1]);
if(Nsv.size() == 3 && Ndv.size() == 3 && first_two_same)
{
// single tet
return false;
}
// https://stackoverflow.com/a/19483741/148668
std::sort(Nsv.begin(), Nsv.end());
std::sort(Ndv.begin(), Ndv.end());
std::vector<int> Nint;
std::set_intersection(
Nsv.begin(), Nsv.end(), Ndv.begin(), Ndv.end(), std::back_inserter(Nint));
// check if edge collapse is valid: intersection of vertex neighbors of s and
// d should be exactly 2+(s,d) = 4
// http://stackoverflow.com/a/27049418/148668
if(Nint.size() != 2)
{
return false;
}
return true;
}
+15
View File
@@ -9,6 +9,7 @@
#define IGL_EDGE_COLLAPSE_IS_VALID_H
#include "igl_inline.h"
#include <Eigen/Core>
#include <vector>
namespace igl
{
// Assumes (V,F) is a closed manifold mesh (except for previouslly collapsed
@@ -37,6 +38,20 @@ namespace igl
const Eigen::VectorXi & EMAP,
const Eigen::MatrixXi & EF,
const Eigen::MatrixXi & EI);
// Inputs:
// Nsv #Nsv list of "next" vertices circulating around starting vertex of
// edge
// Ndv #Ndv list of "next" vertices circulating around destination vertex of
// edge
// Outputs:
// Nsv (side-effect: sorted by value)
// Ndv (side-effect: sorted by value)
// Returns true iff edge collapse is valid
//
// See also: circulation
IGL_INLINE bool edge_collapse_is_valid(
/*const*/ std::vector<int> & Nsv,
/*const*/ std::vector<int> & Ndv);
}
#ifndef IGL_STATIC_LIBRARY
# include "edge_collapse_is_valid.cpp"
+1 -2
View File
@@ -51,8 +51,7 @@ IGL_INLINE void igl::edge_flaps(
Eigen::MatrixXi & EI)
{
Eigen::MatrixXi allE;
std::vector<std::vector<int> > uE2E;
igl::unique_edge_map(F,allE,uE,EMAP,uE2E);
igl::unique_edge_map(F,allE,uE,EMAP);
// Const-ify to call overload
const auto & cuE = uE;
const auto & cEMAP = EMAP;
+1
View File
@@ -1,6 +1,7 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
// Copyright (C) 2020 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+2
View File
@@ -22,6 +22,8 @@ IGL_INLINE void igl::edge_lengths(
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::edge_lengths<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 6, 0, -1, 6> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&);
// generated by autoexplicit.sh
template void igl::edge_lengths<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
// generated by autoexplicit.sh
template void igl::edge_lengths<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+48
View File
@@ -0,0 +1,48 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "edge_midpoints.h"
template<typename DerivedV,typename DerivedF,typename DerivedE,
typename DerivedoE, typename Derivedmps>
IGL_INLINE void
igl::edge_midpoints(
const Eigen::MatrixBase<DerivedV> &V,
const Eigen::MatrixBase<DerivedF> &F,
const Eigen::MatrixBase<DerivedE> &E,
const Eigen::MatrixBase<DerivedoE> &oE,
Eigen::PlainObjectBase<Derivedmps> &mps)
{
assert(E.rows()==F.rows() && "E does not match dimensions of F.");
assert(oE.rows()==F.rows() && "oE does not match dimensions of F.");
assert(E.cols()==3 && F.cols()==3 && oE.cols()==3 &&
"This method is for triangle meshes.");
assert(F.maxCoeff()<V.rows() && "V does not seem to belong to F.");
using ScalarE = typename DerivedE::Scalar;
using ScalarF = typename DerivedF::Scalar;
const ScalarE m = E.maxCoeff()+1;
mps.resize(m, V.cols());
for(Eigen::Index i=0; i<F.rows(); ++i) {
for(int j=0; j<3; ++j) {
if(oE(i,j)<0) {
continue;
}
const ScalarE e = E(i,j);
const ScalarF vi=F(i,(j+1)%3), vj=F(i,(j+2)%3);
mps.row(e) = 0.5*(V.row(vi) + V.row(vj));
}
}
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template void igl::edge_midpoints<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
#endif
+38
View File
@@ -0,0 +1,38 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_EDGE_MIDPOINTS_H
#define IGL_EDGE_MIDPOINTS_H
#include "igl_inline.h"
#include <Eigen/Dense>
namespace igl
{
// Computes the midpoints of edges in a triangle mesh.
//
// Input:
// V, F: triangle mesh
// E, oE: mapping from halfedges to edges and orientation as generated by
// orient_halfedges
//
// Output:
// mps: edge midpoints, one per edge in E
template<typename DerivedV,typename DerivedF,typename DerivedE,
typename DerivedoE, typename Derivedmps>
IGL_INLINE void edge_midpoints(
const Eigen::MatrixBase<DerivedV> &V,
const Eigen::MatrixBase<DerivedF> &F,
const Eigen::MatrixBase<DerivedE> &E,
const Eigen::MatrixBase<DerivedoE> &oE,
Eigen::PlainObjectBase<Derivedmps> &mps);
}
#ifndef IGL_STATIC_LIBRARY
# include "edge_midpoints.cpp"
#endif
#endif
+94
View File
@@ -0,0 +1,94 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "edge_vectors.h"
#include <Eigen/Geometry>
#include "per_face_normals.h"
#include "PI.h"
template<typename DerivedV,typename DerivedF,typename DerivedE,
typename DerivedoE, typename Derivedvec>
IGL_INLINE void
igl::edge_vectors(
const Eigen::MatrixBase<DerivedV> &V,
const Eigen::MatrixBase<DerivedF> &F,
const Eigen::MatrixBase<DerivedE> &E,
const Eigen::MatrixBase<DerivedoE> &oE,
Eigen::PlainObjectBase<Derivedvec> &vec)
{
Eigen::Matrix<typename Derivedvec::Scalar, Eigen::Dynamic, Eigen::Dynamic>
dummy;
edge_vectors<false>(V, F, E, oE, vec, dummy);
}
template<bool computePerpendicular,
typename DerivedV,typename DerivedF,typename DerivedE,
typename DerivedoE, typename DerivedvecParallel,
typename DerivedvecPerpendicular>
IGL_INLINE void
igl::edge_vectors(
const Eigen::MatrixBase<DerivedV> &V,
const Eigen::MatrixBase<DerivedF> &F,
const Eigen::MatrixBase<DerivedE> &E,
const Eigen::MatrixBase<DerivedoE> &oE,
Eigen::PlainObjectBase<DerivedvecParallel> &vecParallel,
Eigen::PlainObjectBase<DerivedvecPerpendicular> &vecPerpendicular)
{
using Scalar = typename DerivedvecParallel::Scalar;
using MatX = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;
assert(E.rows()==F.rows() && "E does not match dimensions of F.");
assert(oE.rows()==F.rows() && "oE does not match dimensions of F.");
assert(E.cols()==3 && F.cols()==3 && oE.cols()==3 &&
"This method is for triangle meshes.");
assert(F.maxCoeff()<V.rows() && "V does not seem to belong to F.");
const typename DerivedE::Scalar m = E.maxCoeff()+1;
//Compute edge-based normal
MatX N, edgeN(m, 3);
edgeN.setZero();
per_face_normals(V, F, N);
for(Eigen::Index i=0; i<E.rows(); ++i) {
for(int j=0; j<3; ++j) {
edgeN.row(E(i,j)) += N.row(i);
}
}
edgeN.rowwise().normalize();
//Compute edge vectors
vecParallel.resize(m, 3);
if(computePerpendicular) { //This should ideally be an if constexpr
vecPerpendicular.resize(m, 3);
}
for(Eigen::Index i=0; i<E.rows(); ++i) {
for(int j=0; j<3; ++j) {
if(oE(i,j)<0) {
continue;
}
const typename DerivedE::Scalar e=E(i,j);
const typename DerivedF::Scalar vi=F(i,(j+1)%3), vj=F(i,(j+2)%3);
vecParallel.row(e) = (V.row(vj)-V.row(vi)).normalized();
if(computePerpendicular) { //This should ideally be an if constexpr
vecPerpendicular.row(e) =
Eigen::AngleAxis<Scalar>(0.5*PI, edgeN.row(e)) *
vecParallel.row(e).transpose();
}
}
}
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template void igl::edge_vectors<true, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
#endif
+68
View File
@@ -0,0 +1,68 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_EDGE_VECTORS_H
#define IGL_EDGE_VECTORS_H
#include "igl_inline.h"
#include <Eigen/Dense>
namespace igl
{
// Computes the normalized edge vectors for edges in a triangle mesh
//
// Input:
// V, F: triangle mesh
// E, oE: mapping from halfedges to edges and orientation as generated by
// orient_halfedges
//
// Output:
// vec: normalized edge vectors for each unique edge in E, according to order
// of E.
template<typename DerivedV,typename DerivedF,typename DerivedE,
typename DerivedoE, typename Derivedvec>
IGL_INLINE void edge_vectors(
const Eigen::MatrixBase<DerivedV> &V,
const Eigen::MatrixBase<DerivedF> &F,
const Eigen::MatrixBase<DerivedE> &E,
const Eigen::MatrixBase<DerivedoE> &oE,
Eigen::PlainObjectBase<Derivedvec> &vec);
// Computes the normalized edge vectors for edges in a triangle mesh
//
// Input:
// V, F: triangle mesh
// E, oE: mapping from halfedges to edges and orientation as generated by
// orient_halfedges
// template parameter computePerpendicular: whether to compute
// vecPerpendicular or not.
//
// Output:
// vecParallel: normalized edge vectors for each unique edge in E, according
// to order of E.
// vecPerpendicular: tangent unit perpendicular vector to each edge, according
// to orientation in oE, corresponds to each vector in
// vecParallel rotated by pi/2 around an edge-based normal.
//
template<bool computePerpendicular=true,
typename DerivedV,typename DerivedF,typename DerivedE,
typename DerivedoE, typename DerivedvecParallel,
typename DerivedvecPerpendicular>
IGL_INLINE void edge_vectors(
const Eigen::MatrixBase<DerivedV> &V,
const Eigen::MatrixBase<DerivedF> &F,
const Eigen::MatrixBase<DerivedE> &E,
const Eigen::MatrixBase<DerivedoE> &oE,
Eigen::PlainObjectBase<DerivedvecParallel> &vecParallel,
Eigen::PlainObjectBase<DerivedvecPerpendicular> &vecPerpendicular);
}
#ifndef IGL_STATIC_LIBRARY
# include "edge_vectors.cpp"
#endif
#endif
+24 -1
View File
@@ -18,6 +18,26 @@ IGL_INLINE void igl::edges(
typedef typename DerivedF::Scalar Index;
Eigen::SparseMatrix<Index> A;
igl::adjacency_matrix(F,A);
igl::edges(A,E);
}
template <typename DerivedI, typename DerivedC, typename DerivedE>
IGL_INLINE void igl::edges(
const Eigen::MatrixBase<DerivedI> & I,
const Eigen::MatrixBase<DerivedC> & C,
Eigen::PlainObjectBase<DerivedE> & E)
{
typedef typename DerivedE::Scalar Index;
Eigen::SparseMatrix<Index> A;
igl::adjacency_matrix(I,C,A);
igl::edges(A,E);
}
template <typename T, typename DerivedE>
IGL_INLINE void igl::edges(
const Eigen::SparseMatrix<T> & A,
Eigen::PlainObjectBase<DerivedE> & E)
{
// Number of non zeros should be twice number of edges
assert(A.nonZeros()%2 == 0);
// Resize to fit edges
@@ -27,7 +47,7 @@ IGL_INLINE void igl::edges(
for(int k=0; k<A.outerSize(); ++k)
{
// Iterate over inside
for(typename Eigen::SparseMatrix<Index>::InnerIterator it (A,k); it; ++it)
for(typename Eigen::SparseMatrix<T>::InnerIterator it (A,k); it; ++it)
{
// only add edge in one direction
if(it.row()<it.col())
@@ -38,10 +58,13 @@ IGL_INLINE void igl::edges(
}
}
}
assert(i == E.rows() && "A should be symmetric");
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::edges<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
template void igl::edges<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
template void igl::edges<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
template void igl::edges<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
+23
View File
@@ -10,6 +10,7 @@
#include "igl_inline.h"
#include <Eigen/Dense>
#include <Eigen/Sparse>
namespace igl
{
@@ -27,6 +28,28 @@ namespace igl
IGL_INLINE void edges(
const Eigen::MatrixBase<DerivedF> & F,
Eigen::PlainObjectBase<DerivedE> & E);
// Constructs a list of unique edges represented in a given 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:
// E #E by 2 list of edges in no particular order
template <typename DerivedI, typename DerivedC, typename DerivedE>
IGL_INLINE void edges(
const Eigen::MatrixBase<DerivedI> & I,
const Eigen::MatrixBase<DerivedC> & C,
Eigen::PlainObjectBase<DerivedE> & E);
// Inputs:
// A #V by #V symmetric adjacency matrix
// Outputs:
// E #E by 2 list of edges in no particular order
template <typename T, typename DerivedE>
IGL_INLINE void edges(
const Eigen::SparseMatrix<T> & A,
Eigen::PlainObjectBase<DerivedE> & E);
}
#ifndef IGL_STATIC_LIBRARY
+86
View File
@@ -0,0 +1,86 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Vladimir Fonov <vladimir.fonov@gmail.com>
// 2013 Alec Jacobson <alecjacobson@gmail.com>
// 2014 Christian Schüller <schuellchr@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_EMBREE_EMBREE_DEVICE_H
#define IGL_EMBREE_EMBREE_DEVICE_H
#include <embree3/rtcore.h>
#include <iostream>
namespace igl
{
namespace embree
{
// keep track of embree device
struct EmbreeDevice
{
RTCDevice embree_device;
int embree_device_cntr;
static EmbreeDevice & instance()
{
static EmbreeDevice s;
return s;
} // instance
EmbreeDevice(const EmbreeDevice &) = delete;
EmbreeDevice & operator = (const EmbreeDevice &) = delete;
static RTCDevice get_device(const char *config=nullptr)
{
return instance().get(config);
}
static void release_device(void)
{
instance().release();
}
private:
EmbreeDevice():embree_device(nullptr),embree_device_cntr(0) {}
~EmbreeDevice()
{
if(embree_device)
rtcReleaseDevice(embree_device);
}
RTCDevice get(const char *config=nullptr)
{
if(!embree_device)
{
embree_device = rtcNewDevice (config);
if(rtcGetDeviceError (embree_device) != RTC_ERROR_NONE)
std::cerr << "Embree: An error occurred while initializing embree core!" << std::endl;
#ifdef IGL_VERBOSE
else
std::cerr << "Embree: core initialized." << std::endl;
#endif
}
++embree_device_cntr;
return embree_device;
}
void release()
{
if(!--embree_device_cntr) {
rtcReleaseDevice (embree_device);
embree_device = nullptr;
#ifdef IGL_VERBOSE
std::cerr << "Embree: core released." << std::endl;
#endif
}
}
};
}
}
#endif // IGL_EMBREE_EMBREE_DEVICE_H
+396
View File
@@ -0,0 +1,396 @@
#include "EmbreeIntersector.h"
// Implementation
#include <igl/EPS.h>
IGL_INLINE igl::embree::EmbreeIntersector::EmbreeIntersector()
:
//scene(NULL),
geomID(0),
vertices(NULL),
triangles(NULL),
initialized(false),
device(igl::embree::EmbreeDevice::get_device())
{
}
IGL_INLINE igl::embree::EmbreeIntersector::EmbreeIntersector(
const EmbreeIntersector &)
:// To make -Weffc++ happy
//scene(NULL),
geomID(0),
vertices(NULL),
triangles(NULL),
initialized(false)
{
assert(false && "Embree: Copying EmbreeIntersector is not allowed");
}
IGL_INLINE igl::embree::EmbreeIntersector & igl::embree::EmbreeIntersector::operator=(
const EmbreeIntersector &)
{
assert(false && "Embree: Assigning an EmbreeIntersector is not allowed");
return *this;
}
IGL_INLINE void igl::embree::EmbreeIntersector::init(
const PointMatrixType& V,
const FaceMatrixType& F,
bool isStatic)
{
std::vector<const PointMatrixType*> Vtemp;
std::vector<const FaceMatrixType*> Ftemp;
std::vector<int> masks;
Vtemp.push_back(&V);
Ftemp.push_back(&F);
masks.push_back(0xFFFFFFFF);
init(Vtemp,Ftemp,masks,isStatic);
}
IGL_INLINE void igl::embree::EmbreeIntersector::init(
const std::vector<const PointMatrixType*>& V,
const std::vector<const FaceMatrixType*>& F,
const std::vector<int>& masks,
bool isStatic)
{
if(initialized)
deinit();
using namespace std;
if(V.size() == 0 || F.size() == 0)
{
std::cerr << "Embree: No geometry specified!";
return;
}
RTCBuildQuality buildQuality = isStatic ? RTC_BUILD_QUALITY_HIGH : RTC_BUILD_QUALITY_MEDIUM;
// create a scene
scene = rtcNewScene(device);
rtcSetSceneFlags(scene, RTC_SCENE_FLAG_ROBUST);
rtcSetSceneBuildQuality(scene, buildQuality);
for(int g=0;g<(int)V.size();g++)
{
// create triangle mesh geometry in that scene
RTCGeometry geom_0 = rtcNewGeometry (device, RTC_GEOMETRY_TYPE_TRIANGLE);
rtcSetGeometryBuildQuality(geom_0,buildQuality);
rtcSetGeometryTimeStepCount(geom_0,1);
geomID = rtcAttachGeometry(scene,geom_0);
rtcReleaseGeometry(geom_0);
// fill vertex buffer
vertices = (Vertex*)rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_VERTEX,0,RTC_FORMAT_FLOAT3,4*sizeof(float),V[g]->rows());
for(int i=0;i<(int)V[g]->rows();i++)
{
vertices[i].x = (float)V[g]->coeff(i,0);
vertices[i].y = (float)V[g]->coeff(i,1);
vertices[i].z = (float)V[g]->coeff(i,2);
}
// fill triangle buffer
triangles = (Triangle*) rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_INDEX,0,RTC_FORMAT_UINT3,3*sizeof(int),F[g]->rows());
for(int i=0;i<(int)F[g]->rows();i++)
{
triangles[i].v0 = (int)F[g]->coeff(i,0);
triangles[i].v1 = (int)F[g]->coeff(i,1);
triangles[i].v2 = (int)F[g]->coeff(i,2);
}
rtcSetGeometryMask(geom_0,masks[g]);
rtcCommitGeometry(geom_0);
}
rtcCommitScene(scene);
if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
std::cerr << "Embree: An error occurred while initializing the provided geometry!" << endl;
#ifdef IGL_VERBOSE
else
std::cerr << "Embree: geometry added." << endl;
#endif
initialized = true;
}
igl::embree::EmbreeIntersector
::~EmbreeIntersector()
{
if(initialized)
deinit();
igl::embree::EmbreeDevice::release_device();
}
void igl::embree::EmbreeIntersector::deinit()
{
if(device && scene)
{
rtcReleaseScene(scene);
if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
{
std::cerr << "Embree: An error occurred while resetting!" << std::endl;
}
#ifdef IGL_VERBOSE
else
{
std::cerr << "Embree: geometry removed." << std::endl;
}
#endif
}
}
IGL_INLINE bool igl::embree::EmbreeIntersector::intersectRay(
const Eigen::RowVector3f& origin,
const Eigen::RowVector3f& direction,
Hit& hit,
float tnear,
float tfar,
int mask) const
{
RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
ray.ray.flags = 0;
createRay(ray, origin,direction,tnear,tfar,mask);
// shot ray
{
RTCIntersectContext context;
rtcInitIntersectContext(&context);
rtcIntersect1(scene,&context,&ray);
ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
ray.hit.Ng_y = -ray.hit.Ng_y;
ray.hit.Ng_z = -ray.hit.Ng_z;
}
#ifdef IGL_VERBOSE
if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
std::cerr << "Embree: An error occurred while resetting!" << std::endl;
#endif
if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
{
hit.id = ray.hit.primID;
hit.gid = ray.hit.geomID;
hit.u = ray.hit.u;
hit.v = ray.hit.v;
hit.t = ray.ray.tfar;
return true;
}
return false;
}
IGL_INLINE bool igl::embree::EmbreeIntersector::intersectBeam(
const Eigen::RowVector3f& origin,
const Eigen::RowVector3f& direction,
Hit& hit,
float tnear,
float tfar,
int mask,
int geoId,
bool closestHit,
unsigned int samples) const
{
bool hasHit = false;
Hit bestHit;
if(closestHit)
bestHit.t = std::numeric_limits<float>::max();
else
bestHit.t = 0;
if((intersectRay(origin,direction,hit,tnear,tfar,mask) && (hit.gid == geoId || geoId == -1)))
{
bestHit = hit;
hasHit = true;
}
// sample points around actual ray (conservative hitcheck)
const float eps= 1e-5;
Eigen::RowVector3f up(0,1,0);
if (direction.cross(up).norm() < eps) up = Eigen::RowVector3f(1,0,0);
Eigen::RowVector3f offset = direction.cross(up).normalized();
Eigen::Matrix3f rot = Eigen::AngleAxis<float>(2*3.14159265358979/samples,direction).toRotationMatrix();
for(int r=0;r<(int)samples;r++)
{
if(intersectRay(origin+offset*eps,direction,hit,tnear,tfar,mask) &&
((closestHit && (hit.t < bestHit.t)) ||
(!closestHit && (hit.t > bestHit.t))) &&
(hit.gid == geoId || geoId == -1))
{
bestHit = hit;
hasHit = true;
}
offset = rot*offset.transpose();
}
hit = bestHit;
return hasHit;
}
IGL_INLINE bool
igl::embree::EmbreeIntersector
::intersectRay(
const Eigen::RowVector3f& origin,
const Eigen::RowVector3f& direction,
std::vector<Hit > &hits,
int& num_rays,
float tnear,
float tfar,
int mask) const
{
using namespace std;
num_rays = 0;
hits.clear();
int last_id0 = -1;
double self_hits = 0;
// This epsilon is directly correleated to the number of missed hits, smaller
// means more accurate and slower
//const double eps = DOUBLE_EPS;
const double eps = FLOAT_EPS;
double min_t = tnear;
bool large_hits_warned = false;
RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
ray.ray.flags = 0;
createRay(ray,origin,direction,tnear,tfar,mask);
while(true)
{
ray.ray.tnear = min_t;
ray.ray.tfar = tfar;
ray.hit.geomID = RTC_INVALID_GEOMETRY_ID;
ray.hit.primID = RTC_INVALID_GEOMETRY_ID;
ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
num_rays++;
{
RTCIntersectContext context;
rtcInitIntersectContext(&context);
rtcIntersect1(scene,&context,&ray);
ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
ray.hit.Ng_y = -ray.hit.Ng_y;
ray.hit.Ng_z = -ray.hit.Ng_z;
}
if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
{
// Hit self again, progressively advance
if(ray.hit.primID == last_id0 || ray.ray.tfar <= min_t)
{
// push min_t a bit more
//double t_push = pow(2.0,self_hits-4)*(hit.t<eps?eps:hit.t);
double t_push = pow(2.0,self_hits)*eps;
#ifdef IGL_VERBOSE
std::cerr<<" t_push: "<<t_push<<endl;
#endif
//o = o+t_push*d;
min_t += t_push;
self_hits++;
}
else
{
Hit hit;
hit.id = ray.hit.primID;
hit.gid = ray.hit.geomID;
hit.u = ray.hit.u;
hit.v = ray.hit.v;
hit.t = ray.ray.tfar;
hits.push_back(hit);
#ifdef IGL_VERBOSE
std::cerr<<" t: "<<hit.t<<endl;
#endif
// Instead of moving origin, just change min_t. That way calculations
// all use exactly same origin values
min_t = ray.ray.tfar;
// reset t_scale
self_hits = 0;
}
last_id0 = ray.hit.primID;
}
else
break; // no more hits
if(hits.size()>1000 && !large_hits_warned)
{
std::cout<<"Warning: Large number of hits..."<<endl;
std::cout<<"[ ";
for(vector<Hit>::iterator hit = hits.begin(); hit != hits.end();hit++)
{
std::cout<<(hit->id+1)<<" ";
}
std::cout.precision(std::numeric_limits< double >::digits10);
std::cout<<"[ ";
for(vector<Hit>::iterator hit = hits.begin(); hit != hits.end(); hit++)
{
std::cout<<(hit->t)<<endl;;
}
std::cout<<"]"<<endl;
large_hits_warned = true;
return hits.empty();
}
}
return hits.empty();
}
IGL_INLINE bool
igl::embree::EmbreeIntersector
::intersectSegment(const Eigen::RowVector3f& a, const Eigen::RowVector3f& ab, Hit &hit, int mask) const
{
RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
ray.ray.flags = 0;
createRay(ray,a,ab,0,1.0,mask);
{
RTCIntersectContext context;
rtcInitIntersectContext(&context);
rtcIntersect1(scene,&context,&ray);
ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
ray.hit.Ng_y = -ray.hit.Ng_y;
ray.hit.Ng_z = -ray.hit.Ng_z;
}
if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
{
hit.id = ray.hit.primID;
hit.gid = ray.hit.geomID;
hit.u = ray.hit.u;
hit.v = ray.hit.v;
hit.t = ray.ray.tfar;
return true;
}
return false;
}
IGL_INLINE void
igl::embree::EmbreeIntersector
::createRay(RTCRayHit& ray, const Eigen::RowVector3f& origin, const Eigen::RowVector3f& direction, float tnear, float tfar, int mask) const
{
ray.ray.org_x = origin[0];
ray.ray.org_y = origin[1];
ray.ray.org_z = origin[2];
ray.ray.dir_x = direction[0];
ray.ray.dir_y = direction[1];
ray.ray.dir_z = direction[2];
ray.ray.tnear = tnear;
ray.ray.tfar = tfar;
ray.ray.id = RTC_INVALID_GEOMETRY_ID;
ray.ray.mask = mask;
ray.ray.time = 0.0f;
ray.hit.geomID = RTC_INVALID_GEOMETRY_ID;
ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
ray.hit.primID = RTC_INVALID_GEOMETRY_ID;
}
+18 -445
View File
@@ -19,38 +19,31 @@
#include "../Hit.h"
#include <Eigen/Geometry>
#include <Eigen/Core>
#include <Eigen/Geometry>
#include <embree3/rtcore.h>
#include <embree3/rtcore_ray.h>
#include <iostream>
#include <vector>
#include "EmbreeDevice.h"
namespace igl
{
namespace embree
{
class EmbreeIntersector
{
public:
// Initialize embree engine. This will be called on instance `init()`
// calls. If already inited then this function does nothing: it is harmless
// to call more than once.
static inline void global_init();
private:
// Deinitialize the embree engine.
static inline void global_deinit();
public:
typedef Eigen::Matrix<float,Eigen::Dynamic,3> PointMatrixType;
typedef Eigen::Matrix<int,Eigen::Dynamic,3> FaceMatrixType;
public:
inline EmbreeIntersector();
EmbreeIntersector();
private:
// Copying and assignment are not allowed.
inline EmbreeIntersector(const EmbreeIntersector & that);
inline EmbreeIntersector & operator=(const EmbreeIntersector &);
EmbreeIntersector(const EmbreeIntersector & that);
EmbreeIntersector & operator=(const EmbreeIntersector &);
public:
virtual inline ~EmbreeIntersector();
virtual ~EmbreeIntersector();
// Initialize with a given mesh.
//
@@ -60,7 +53,7 @@ namespace igl
// isStatic scene is optimized for static geometry
// Side effects:
// The first time this is ever called the embree engine is initialized.
inline void init(
void init(
const PointMatrixType& V,
const FaceMatrixType& F,
bool isStatic = false);
@@ -74,7 +67,7 @@ namespace igl
// isStatic scene is optimized for static geometry
// Side effects:
// The first time this is ever called the embree engine is initialized.
inline void init(
void init(
const std::vector<const PointMatrixType*>& V,
const std::vector<const FaceMatrixType*>& F,
const std::vector<int>& masks,
@@ -83,7 +76,7 @@ namespace igl
// Deinitialize embree datasctructures for current mesh. Also called on
// destruction: no need to call if you just want to init() once and
// destroy.
inline void deinit();
void deinit();
// Given a ray find the first hit
//
@@ -96,7 +89,7 @@ namespace igl
// Output:
// hit information about hit
// Returns true if and only if there was a hit
inline bool intersectRay(
bool intersectRay(
const Eigen::RowVector3f& origin,
const Eigen::RowVector3f& direction,
Hit& hit,
@@ -119,7 +112,7 @@ namespace igl
// Output:
// hit information about hit
// Returns true if and only if there was a hit
inline bool intersectBeam(
bool intersectBeam(
const Eigen::RowVector3f& origin,
const Eigen::RowVector3f& direction,
Hit& hit,
@@ -142,7 +135,7 @@ namespace igl
// hit information about hit
// num_rays number of rays shot (at least one)
// Returns true if and only if there was a hit
inline bool intersectRay(
bool intersectRay(
const Eigen::RowVector3f& origin,
const Eigen::RowVector3f& direction,
std::vector<Hit > &hits,
@@ -159,7 +152,7 @@ namespace igl
// Output:
// hit information about hit
// Returns true if and only if there was a hit
inline bool intersectSegment(
bool intersectSegment(
const Eigen::RowVector3f& a,
const Eigen::RowVector3f& ab,
Hit &hit,
@@ -176,7 +169,9 @@ namespace igl
Triangle* triangles;
bool initialized;
inline void createRay(
RTCDevice device;
void createRay(
RTCRayHit& ray,
const Eigen::RowVector3f& origin,
const Eigen::RowVector3f& direction,
@@ -187,430 +182,8 @@ namespace igl
}
}
// Implementation
#include <igl/EPS.h>
// This unfortunately cannot be a static field of EmbreeIntersector because it
// would depend on the template and then we might end up with initializing
// embree twice. If only there was a way to ask embree if it's already
// initialized...
namespace igl
{
namespace embree
{
// Keeps track of whether the **Global** Embree intersector has been
// initialized. This should never been done at the global scope.
static RTCDevice g_device = nullptr;
}
}
inline void igl::embree::EmbreeIntersector::global_init()
{
if(!g_device)
{
g_device = rtcNewDevice (NULL);
if(rtcGetDeviceError (g_device) != RTC_ERROR_NONE)
std::cerr << "Embree: An error occurred while initializing embree core!" << std::endl;
#ifdef IGL_VERBOSE
else
std::cerr << "Embree: core initialized." << std::endl;
#ifndef IGL_STATIC_LIBRARY
# include "EmbreeIntersector.cpp"
#endif
}
}
inline void igl::embree::EmbreeIntersector::global_deinit()
{
rtcReleaseDevice (g_device);
g_device = nullptr;
}
inline igl::embree::EmbreeIntersector::EmbreeIntersector()
:
//scene(NULL),
geomID(0),
vertices(NULL),
triangles(NULL),
initialized(false)
{
}
inline igl::embree::EmbreeIntersector::EmbreeIntersector(
const EmbreeIntersector &)
:// To make -Weffc++ happy
//scene(NULL),
geomID(0),
vertices(NULL),
triangles(NULL),
initialized(false)
{
assert(false && "Embree: Copying EmbreeIntersector is not allowed");
}
inline igl::embree::EmbreeIntersector & igl::embree::EmbreeIntersector::operator=(
const EmbreeIntersector &)
{
assert(false && "Embree: Assigning an EmbreeIntersector is not allowed");
return *this;
}
inline void igl::embree::EmbreeIntersector::init(
const PointMatrixType& V,
const FaceMatrixType& F,
bool isStatic)
{
std::vector<const PointMatrixType*> Vtemp;
std::vector<const FaceMatrixType*> Ftemp;
std::vector<int> masks;
Vtemp.push_back(&V);
Ftemp.push_back(&F);
masks.push_back(0xFFFFFFFF);
init(Vtemp,Ftemp,masks,isStatic);
}
inline void igl::embree::EmbreeIntersector::init(
const std::vector<const PointMatrixType*>& V,
const std::vector<const FaceMatrixType*>& F,
const std::vector<int>& masks,
bool isStatic)
{
if(initialized)
deinit();
using namespace std;
global_init();
if(V.size() == 0 || F.size() == 0)
{
std::cerr << "Embree: No geometry specified!";
return;
}
RTCBuildQuality buildQuality = isStatic ? RTC_BUILD_QUALITY_HIGH : RTC_BUILD_QUALITY_MEDIUM;
// create a scene
scene = rtcNewScene(g_device);
rtcSetSceneFlags(scene, RTC_SCENE_FLAG_ROBUST);
rtcSetSceneBuildQuality(scene, buildQuality);
for(int g=0;g<(int)V.size();g++)
{
// create triangle mesh geometry in that scene
RTCGeometry geom_0 = rtcNewGeometry (g_device, RTC_GEOMETRY_TYPE_TRIANGLE);
rtcSetGeometryBuildQuality(geom_0,buildQuality);
rtcSetGeometryTimeStepCount(geom_0,1);
geomID = rtcAttachGeometry(scene,geom_0);
rtcReleaseGeometry(geom_0);
// fill vertex buffer
vertices = (Vertex*)rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_VERTEX,0,RTC_FORMAT_FLOAT3,4*sizeof(float),V[g]->rows());
for(int i=0;i<(int)V[g]->rows();i++)
{
vertices[i].x = (float)V[g]->coeff(i,0);
vertices[i].y = (float)V[g]->coeff(i,1);
vertices[i].z = (float)V[g]->coeff(i,2);
}
// fill triangle buffer
triangles = (Triangle*) rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_INDEX,0,RTC_FORMAT_UINT3,3*sizeof(int),F[g]->rows());
for(int i=0;i<(int)F[g]->rows();i++)
{
triangles[i].v0 = (int)F[g]->coeff(i,0);
triangles[i].v1 = (int)F[g]->coeff(i,1);
triangles[i].v2 = (int)F[g]->coeff(i,2);
}
rtcSetGeometryMask(geom_0,masks[g]);
rtcCommitGeometry(geom_0);
}
rtcCommitScene(scene);
if(rtcGetDeviceError (g_device) != RTC_ERROR_NONE)
std::cerr << "Embree: An error occurred while initializing the provided geometry!" << endl;
#ifdef IGL_VERBOSE
else
std::cerr << "Embree: geometry added." << endl;
#endif
initialized = true;
}
igl::embree::EmbreeIntersector
::~EmbreeIntersector()
{
if(initialized)
deinit();
}
void igl::embree::EmbreeIntersector::deinit()
{
if(g_device && scene)
{
rtcReleaseScene(scene);
if(rtcGetDeviceError (g_device) != RTC_ERROR_NONE)
{
std::cerr << "Embree: An error occurred while resetting!" << std::endl;
}
#ifdef IGL_VERBOSE
else
{
std::cerr << "Embree: geometry removed." << std::endl;
}
#endif
}
}
inline bool igl::embree::EmbreeIntersector::intersectRay(
const Eigen::RowVector3f& origin,
const Eigen::RowVector3f& direction,
Hit& hit,
float tnear,
float tfar,
int mask) const
{
RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
ray.ray.flags = 0;
createRay(ray, origin,direction,tnear,tfar,mask);
// shot ray
{
RTCIntersectContext context;
rtcInitIntersectContext(&context);
rtcIntersect1(scene,&context,&ray);
ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
ray.hit.Ng_y = -ray.hit.Ng_y;
ray.hit.Ng_z = -ray.hit.Ng_z;
}
#ifdef IGL_VERBOSE
if(rtcGetDeviceError (g_device) != RTC_ERROR_NONE)
std::cerr << "Embree: An error occurred while resetting!" << std::endl;
#endif
if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
{
hit.id = ray.hit.primID;
hit.gid = ray.hit.geomID;
hit.u = ray.hit.u;
hit.v = ray.hit.v;
hit.t = ray.ray.tfar;
return true;
}
return false;
}
inline bool igl::embree::EmbreeIntersector::intersectBeam(
const Eigen::RowVector3f& origin,
const Eigen::RowVector3f& direction,
Hit& hit,
float tnear,
float tfar,
int mask,
int geoId,
bool closestHit,
unsigned int samples) const
{
bool hasHit = false;
Hit bestHit;
if(closestHit)
bestHit.t = std::numeric_limits<float>::max();
else
bestHit.t = 0;
if((intersectRay(origin,direction,hit,tnear,tfar,mask) && (hit.gid == geoId || geoId == -1)))
{
bestHit = hit;
hasHit = true;
}
// sample points around actual ray (conservative hitcheck)
const float eps= 1e-5;
Eigen::RowVector3f up(0,1,0);
if (direction.cross(up).norm() < eps) up = Eigen::RowVector3f(1,0,0);
Eigen::RowVector3f offset = direction.cross(up).normalized();
Eigen::Matrix3f rot = Eigen::AngleAxis<float>(2*3.14159265358979/samples,direction).toRotationMatrix();
for(int r=0;r<(int)samples;r++)
{
if(intersectRay(origin+offset*eps,direction,hit,tnear,tfar,mask) &&
((closestHit && (hit.t < bestHit.t)) ||
(!closestHit && (hit.t > bestHit.t))) &&
(hit.gid == geoId || geoId == -1))
{
bestHit = hit;
hasHit = true;
}
offset = rot*offset.transpose();
}
hit = bestHit;
return hasHit;
}
inline bool
igl::embree::EmbreeIntersector
::intersectRay(
const Eigen::RowVector3f& origin,
const Eigen::RowVector3f& direction,
std::vector<Hit > &hits,
int& num_rays,
float tnear,
float tfar,
int mask) const
{
using namespace std;
num_rays = 0;
hits.clear();
int last_id0 = -1;
double self_hits = 0;
// This epsilon is directly correleated to the number of missed hits, smaller
// means more accurate and slower
//const double eps = DOUBLE_EPS;
const double eps = FLOAT_EPS;
double min_t = tnear;
bool large_hits_warned = false;
RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
ray.ray.flags = 0;
createRay(ray,origin,direction,tnear,tfar,mask);
while(true)
{
ray.ray.tnear = min_t;
ray.ray.tfar = tfar;
ray.hit.geomID = RTC_INVALID_GEOMETRY_ID;
ray.hit.primID = RTC_INVALID_GEOMETRY_ID;
ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
num_rays++;
{
RTCIntersectContext context;
rtcInitIntersectContext(&context);
rtcIntersect1(scene,&context,&ray);
ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
ray.hit.Ng_y = -ray.hit.Ng_y;
ray.hit.Ng_z = -ray.hit.Ng_z;
}
if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
{
// Hit self again, progressively advance
if(ray.hit.primID == last_id0 || ray.ray.tfar <= min_t)
{
// push min_t a bit more
//double t_push = pow(2.0,self_hits-4)*(hit.t<eps?eps:hit.t);
double t_push = pow(2.0,self_hits)*eps;
#ifdef IGL_VERBOSE
std::cerr<<" t_push: "<<t_push<<endl;
#endif
//o = o+t_push*d;
min_t += t_push;
self_hits++;
}
else
{
Hit hit;
hit.id = ray.hit.primID;
hit.gid = ray.hit.geomID;
hit.u = ray.hit.u;
hit.v = ray.hit.v;
hit.t = ray.ray.tfar;
hits.push_back(hit);
#ifdef IGL_VERBOSE
std::cerr<<" t: "<<hit.t<<endl;
#endif
// Instead of moving origin, just change min_t. That way calculations
// all use exactly same origin values
min_t = ray.ray.tfar;
// reset t_scale
self_hits = 0;
}
last_id0 = ray.hit.primID;
}
else
break; // no more hits
if(hits.size()>1000 && !large_hits_warned)
{
std::cout<<"Warning: Large number of hits..."<<endl;
std::cout<<"[ ";
for(vector<Hit>::iterator hit = hits.begin(); hit != hits.end();hit++)
{
std::cout<<(hit->id+1)<<" ";
}
std::cout.precision(std::numeric_limits< double >::digits10);
std::cout<<"[ ";
for(vector<Hit>::iterator hit = hits.begin(); hit != hits.end(); hit++)
{
std::cout<<(hit->t)<<endl;;
}
std::cout<<"]"<<endl;
large_hits_warned = true;
return hits.empty();
}
}
return hits.empty();
}
inline bool
igl::embree::EmbreeIntersector
::intersectSegment(const Eigen::RowVector3f& a, const Eigen::RowVector3f& ab, Hit &hit, int mask) const
{
RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
ray.ray.flags = 0;
createRay(ray,a,ab,0,1.0,mask);
{
RTCIntersectContext context;
rtcInitIntersectContext(&context);
rtcIntersect1(scene,&context,&ray);
ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
ray.hit.Ng_y = -ray.hit.Ng_y;
ray.hit.Ng_z = -ray.hit.Ng_z;
}
if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
{
hit.id = ray.hit.primID;
hit.gid = ray.hit.geomID;
hit.u = ray.hit.u;
hit.v = ray.hit.v;
hit.t = ray.ray.tfar;
return true;
}
return false;
}
inline void
igl::embree::EmbreeIntersector
::createRay(RTCRayHit& ray, const Eigen::RowVector3f& origin, const Eigen::RowVector3f& direction, float tnear, float tfar, int mask) const
{
ray.ray.org_x = origin[0];
ray.ray.org_y = origin[1];
ray.ray.org_z = origin[2];
ray.ray.dir_x = direction[0];
ray.ray.dir_y = direction[1];
ray.ray.dir_z = direction[2];
ray.ray.tnear = tnear;
ray.ray.tfar = tfar;
ray.ray.id = RTC_INVALID_GEOMETRY_ID;
ray.ray.mask = mask;
ray.ray.time = 0.0f;
ray.hit.geomID = RTC_INVALID_GEOMETRY_ID;
ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
ray.hit.primID = RTC_INVALID_GEOMETRY_ID;
}
#endif //EMBREE_INTERSECTOR_H
+423
View File
@@ -0,0 +1,423 @@
#include "EmbreeRenderer.h"
// Implementation
//IGL viewing parts
#include "../unproject.h"
#include "../look_at.h"
#include "../frustum.h"
#include "../ortho.h"
// color map
#include "../jet.h"
#include "../PI.h"
IGL_INLINE void igl::embree::EmbreeRenderer::init_view()
{
camera_base_zoom = 1.0f;
camera_zoom = 1.0f;
camera_view_angle = 45.0;
camera_dnear = 1.0;
camera_dfar = 100.0;
camera_base_translation << 0, 0, 0;
camera_translation << 0, 0, 0;
camera_eye << 0, 0, 5;
camera_center << 0, 0, 0;
camera_up << 0, 1, 0;
rot_matrix = Eigen::Matrix3f::Identity();
view = Eigen::Matrix4f::Identity();
proj = Eigen::Matrix4f::Identity();
norm = Eigen::Matrix4f::Identity();
orthographic = false;
uC << 1,0,0;
}
IGL_INLINE igl::embree::EmbreeRenderer::EmbreeRenderer()
:
scene(NULL),
geomID(0),
initialized(false),
device(igl::embree::EmbreeDevice::get_device())
{
init_view();
}
IGL_INLINE igl::embree::EmbreeRenderer::EmbreeRenderer(
const EmbreeRenderer &)
:// To make -Weffc++ happy
scene(NULL),
geomID(0),
initialized(false)
{
assert(false && "Embree: Copying EmbreeRenderer is not allowed");
}
IGL_INLINE igl::embree::EmbreeRenderer & igl::embree::EmbreeRenderer::operator=(
const EmbreeRenderer &)
{
assert(false && "Embree: Assigning an EmbreeRenderer is not allowed");
return *this;
}
IGL_INLINE void igl::embree::EmbreeRenderer::init(
const PointMatrixType& V,
const FaceMatrixType& F,
bool isStatic)
{
std::vector<const PointMatrixType*> Vtemp;
std::vector<const FaceMatrixType*> Ftemp;
std::vector<int> masks;
Vtemp.push_back(&V);
Ftemp.push_back(&F);
masks.push_back(0xFFFFFFFF);
init(Vtemp,Ftemp,masks,isStatic);
}
IGL_INLINE void igl::embree::EmbreeRenderer::init(
const std::vector<const PointMatrixType*>& V,
const std::vector<const FaceMatrixType*>& F,
const std::vector<int>& masks,
bool isStatic)
{
if(initialized)
deinit();
using namespace std;
if(V.size() == 0 || F.size() == 0)
{
std::cerr << "Embree: No geometry specified!";
return;
}
RTCBuildQuality buildQuality = isStatic ? RTC_BUILD_QUALITY_HIGH : RTC_BUILD_QUALITY_MEDIUM;
// create a scene
scene = rtcNewScene(device);
rtcSetSceneFlags(scene, RTC_SCENE_FLAG_ROBUST);
rtcSetSceneBuildQuality(scene, buildQuality);
for(int g=0;g<(int)V.size();g++)
{
// create triangle mesh geometry in that scene
RTCGeometry geom_0 = rtcNewGeometry (device, RTC_GEOMETRY_TYPE_TRIANGLE);
rtcSetGeometryBuildQuality(geom_0, buildQuality);
rtcSetGeometryTimeStepCount(geom_0,1);
geomID = rtcAttachGeometry(scene,geom_0);
rtcReleaseGeometry(geom_0);
// fill vertex buffer, have to be 16 byte wide( sizeof(float)*4 )
Eigen::Map<Eigen::Matrix<float,-1,4,Eigen::RowMajor>> vertices(
(float*)rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_VERTEX,0,RTC_FORMAT_FLOAT3,4*sizeof(float),V[g]->rows()),
V[g]->rows(),4
);
vertices.block(0,0,V[g]->rows(),3) = V[g]->cast<float>();
// fill triangle buffer
Eigen::Map<Eigen::Matrix<unsigned int,-1,3,Eigen::RowMajor>> triangles(
(unsigned int*) rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_INDEX,0,RTC_FORMAT_UINT3,3*sizeof(unsigned int), F[g]->rows()),
F[g]->rows(),3
);
triangles = F[g]->cast<unsigned int>();
//TODO: store vertices and triangles in array for whatever reason?
rtcSetGeometryMask(geom_0, masks[g]);
rtcCommitGeometry(geom_0);
}
rtcCommitScene(scene);
if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
std::cerr << "Embree: An error occurred while initializing the provided geometry!" << endl;
#ifdef IGL_VERBOSE
else
std::cerr << "Embree: geometry added." << endl;
#endif
initialized = true;
}
IGL_INLINE igl::embree::EmbreeRenderer::~EmbreeRenderer()
{
if(initialized)
deinit();
igl::embree::EmbreeDevice::release_device();
}
IGL_INLINE void igl::embree::EmbreeRenderer::deinit()
{
if(scene)
{
rtcReleaseScene(scene);
if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
{
std::cerr << "Embree: An error occurred while resetting!" << std::endl;
}
#ifdef IGL_VERBOSE
else
{
std::cerr << "Embree: geometry removed." << std::endl;
}
#endif
}
}
IGL_INLINE bool igl::embree::EmbreeRenderer::intersect_ray(
const Eigen::RowVector3f& origin,
const Eigen::RowVector3f& direction,
Hit& hit,
float tnear,
float tfar,
int mask) const
{
RTCRayHit ray;
ray.ray.flags = 0;
create_ray(ray, origin,direction,tnear,tfar,mask);
// shot ray
{
RTCIntersectContext context;
rtcInitIntersectContext(&context);
rtcIntersect1(scene, &context, &ray);
ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
ray.hit.Ng_y = -ray.hit.Ng_y;
ray.hit.Ng_z = -ray.hit.Ng_z;
}
#ifdef IGL_VERBOSE
if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
std::cerr << "Embree: An error occurred while resetting!" << std::endl;
#endif
if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
{
hit.id = ray.hit.primID;
hit.gid = ray.hit.geomID;
hit.u = ray.hit.u;
hit.v = ray.hit.v;
hit.t = ray.ray.tfar;
hit.N = Vec3f(ray.hit.Ng_x, ray.hit.Ng_y, ray.hit.Ng_z);
return true;
}
return false;
}
IGL_INLINE void
igl::embree::EmbreeRenderer
::create_ray(RTCRayHit& ray, const Eigen::RowVector3f& origin,
const Eigen::RowVector3f& direction, float tnear, float tfar, int mask) const
{
ray.ray.org_x = origin[0];
ray.ray.org_y = origin[1];
ray.ray.org_z = origin[2];
ray.ray.dir_x = direction[0];
ray.ray.dir_y = direction[1];
ray.ray.dir_z = direction[2];
ray.ray.tnear = tnear;
ray.ray.tfar = tfar;
ray.ray.id = RTC_INVALID_GEOMETRY_ID;
ray.ray.mask = mask;
ray.ray.time = 0.0f;
ray.hit.geomID = RTC_INVALID_GEOMETRY_ID;
ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
ray.hit.primID = RTC_INVALID_GEOMETRY_ID;
}
IGL_INLINE void
igl::embree::EmbreeRenderer
::set_mesh(const Eigen::Matrix<double,Eigen::Dynamic,3> & MV,
const Eigen::Matrix<int, Eigen::Dynamic,3> & MF,
bool is_static)
{
V = MV.cast<float>();
F = MF;
this->init(V,F,is_static);
auto min_point = V.colwise().minCoeff();
auto max_point = V.colwise().maxCoeff();
auto centroid = (0.5*(min_point + max_point)).eval();
camera_base_translation.setConstant(0);
camera_base_translation.head(centroid.size()) = -centroid.cast<float>();
camera_base_zoom = 2.0 / (max_point-min_point).array().abs().maxCoeff();
}
IGL_INLINE void
igl::embree::EmbreeRenderer
::render_buffer(PixelMatrixType& R, PixelMatrixType&G, PixelMatrixType &B,PixelMatrixType &A)
{
assert(R.rows()==G.rows());assert(R.rows()==B.rows());assert(R.rows()==A.rows());
assert(R.cols()==G.cols());assert(R.cols()==B.cols());assert(R.cols()==A.cols());
Eigen::Vector4f viewport(0,0,R.rows(),R.cols());
float width = R.rows();
float height = R.cols();
// update view matrix
igl::look_at( camera_eye, camera_center, camera_up, view);
view = view
* (rot_matrix * Eigen::Scaling(camera_zoom * camera_base_zoom)
* Eigen::Translation3f(camera_translation + camera_base_translation)).matrix();
if (orthographic)
{
float length = (camera_eye - camera_center).norm();
float h = tan(camera_view_angle/360.0 * igl::PI) * (length);
igl::ortho(-h*width/height, h*width/height, -h, h, camera_dnear, camera_dfar, proj);
} else {
float fH = tan(camera_view_angle / 360.0 * igl::PI) * camera_dnear;
float fW = fH * (double)width/(double)height;
igl::frustum(-fW, fW, -fH, fH, camera_dnear, camera_dfar, proj);
}
// go over all pixels in the "view"
for(int x=0;x<(int)width;++x)
{
for(int y=0;y<(int)height;++y)
{
Vec3f s,d,dir;
igl::embree::EmbreeRenderer::Hit hit;
// look into the screen
Vec3f win_s(x,y,0);
Vec3f win_d(x,y,1);
// Source, destination and direction in world
igl::unproject(win_s,this->view,this->proj,viewport,s);
igl::unproject(win_d,this->view,this->proj,viewport,d);
dir = d-s;
dir.normalize();
auto clamp=[](float x)->unsigned char {return (unsigned char)(x<0?0:x>1.0?255:x*255);};
if(this->intersect_ray(s,dir,hit))
{
if ( dir.dot(hit.N) > 0.0f)
{
// TODO: interpolate normals ?
hit.N.normalize();
// cos between ray and face normal
float face_proj=dir.dot(hit.N);
Eigen::RowVector3f c;
if(this->uniform_color)
{
// same color for the whole mesh
c=uC;
} else if(this->face_based) {
// flat color per face
c=this->C.row(hit.id);
} else { //use barycentric coordinates to interpolate colour
c=this->C.row(F(hit.id,1))*hit.u+
this->C.row(F(hit.id,2))*hit.v+
this->C.row(F(hit.id,0))*(1.0-hit.u-hit.v);
}
R(x,y) = clamp(face_proj*c(0));
G(x,y) = clamp(face_proj*c(1));
B(x,y) = clamp(face_proj*c(2));
}
// give the same alpha to all points with something behind
A(x,y)=255;
} else {
R(x,y)=0;
G(x,y)=0;
B(x,y)=0;
A(x,y)=0;
}
}
}
}
IGL_INLINE void
igl::embree::EmbreeRenderer
::set_colors(const Eigen::MatrixXd & C)
{
if(C.rows()==V.rows()) // per vertex color
{
face_based = false;
this->C = C.cast<float>();
this->uniform_color=false;
} else if (C.rows()==F.rows()) {
face_based = true;
this->C = C.cast<float>();
this->uniform_color=false;
} else if (C.rows()==1) {
face_based = true;
this->uC = C.cast<float>();
this->uniform_color=true;
}else {
// don't know what to do
this->uniform_color=true;
assert(false); //?
}
}
IGL_INLINE void
igl::embree::EmbreeRenderer
::set_data(const Eigen::VectorXd & D, igl::ColorMapType cmap)
{
const double caxis_min = D.minCoeff();
const double caxis_max = D.maxCoeff();
return set_data(D,caxis_min,caxis_max,cmap);
}
IGL_INLINE void igl::embree::EmbreeRenderer::set_data(
const Eigen::VectorXd & D,
double caxis_min,
double caxis_max,
igl::ColorMapType cmap)
{
Eigen::MatrixXd C;
igl::colormap(cmap,D,caxis_min,caxis_max,C);
set_colors(C);
}
IGL_INLINE void
igl::embree::EmbreeRenderer::set_rot(const Eigen::Matrix3d &r)
{
this->rot_matrix = r.cast<float>();
}
IGL_INLINE void
igl::embree::EmbreeRenderer::set_zoom(double zoom)
{
this->camera_zoom=zoom;
}
IGL_INLINE void
igl::embree::EmbreeRenderer::set_translation(const Eigen::Vector3d &tr)
{
this->camera_translation=tr.cast<float>();
}
IGL_INLINE void
igl::embree::EmbreeRenderer::set_face_based(bool _f)
{
this->face_based=_f;
}
IGL_INLINE void
igl::embree::EmbreeRenderer::set_orthographic(bool o)
{
this->orthographic=o;
}
#ifdef IGL_STATIC_LIBRARY
#endif //IGL_STATIC_LIBRARY
+248
View File
@@ -0,0 +1,248 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
//
// Copyright (C) 2020 Vladimir Fonov <vladimir.fonov@gmail.com>
// 2013 Alec Jacobson <alecjacobson@gmail.com>
// 2014 Christian Schüller <schuellchr@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_EMBREE_EMBREE_RENDERER_H
#define IGL_EMBREE_EMBREE_RENDERER_H
#include <igl/colormap.h>
#include <Eigen/Geometry>
#include <Eigen/Core>
#include <Eigen/Geometry>
#include <embree3/rtcore.h>
#include <embree3/rtcore_ray.h>
#include <iostream>
#include <vector>
#include "EmbreeDevice.h"
namespace igl
{
namespace embree
{
// embree-based mesh renderer
class EmbreeRenderer
{
public:
typedef Eigen::RowVector3f Vec3f;
struct Hit
{
int id; // primitive id
int gid; // geometry id
float u,v; // barycentric coordinates
float t; // distance = direction*t to intersection
Vec3f N; // element normal
};
public:
typedef Eigen::Matrix<float,Eigen::Dynamic,3> PointMatrixType;
typedef Eigen::Matrix<float,Eigen::Dynamic,3> ColorMatrixType;
typedef Eigen::Matrix<int, Eigen::Dynamic,3> FaceMatrixType;
typedef Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> PixelMatrixType;
public:
EmbreeRenderer();
private:
// Copying and assignment are not allowed.
EmbreeRenderer(const EmbreeRenderer & that);
EmbreeRenderer & operator=(const EmbreeRenderer &);
public:
virtual ~EmbreeRenderer();
// Specify mesh, this call reinitializes embree structures
// Inputs:
// V #V x dim matrix of vertex coordinates
// F #F x simplex_size matrix of indices of simplex corners into V
// is_static - optimize for static thene (HQ rendering)
void set_mesh(const Eigen::Matrix<double,Eigen::Dynamic,3> & V,
const Eigen::Matrix<int, Eigen::Dynamic,3> & F,
bool is_static=true);
// Specify per-vertex or per-face color
// Inputs:
// C #V x 3 matrix of vertex colors
// or #F x 3 matrix of face colors
// or 1 x 3 matrix of uniform color
void set_colors(const Eigen::MatrixXd & C);
// Use min(D) and max(D) to set caxis.
void set_data(const Eigen::VectorXd & D,
igl::ColorMapType cmap = igl::COLOR_MAP_TYPE_VIRIDIS);
// Specify per-vertex or per-face scalar field
// that will be converted to color using jet color map
// Inputs:
// caxis_min caxis minimum bound
// caxis_max caxis maximum bound
// D #V by 1 list of scalar values
// cmap colormap type
// num_steps number of intervals to discretize the colormap
void set_data(
const Eigen::VectorXd & D,
double caxis_min,
double caxis_max,
igl::ColorMapType cmap = igl::COLOR_MAP_TYPE_VIRIDIS);
// Specify mesh rotation
// Inputs:
// r 3 x 3 rotaton matrix
void set_rot(const Eigen::Matrix3d &r);
// Specify mesh magnification
// Inputs:
// z magnification ratio
void set_zoom(double z);
// Specify mesh translation
// Inputs:
// tr translation vector
void set_translation(const Eigen::Vector3d &tr);
// Specify that color is face based
// Inputs:
// f - face or vertex colours
void set_face_based(bool f);
// Use orthographic projection
// Inputs:
// f - orthographic or perspective projection
void set_orthographic(bool f );
// render full buffer
// Outputs:
// all outputs should have the same size (size of the output picture)
// area outside of the visible object will have zero alpha component (transparant)
// R - red channel
// G - green channel
// B - blue channel
// A - alpha channel
void render_buffer(PixelMatrixType &R,
PixelMatrixType &G,
PixelMatrixType &B,
PixelMatrixType &A);
// Given a ray find the first hit
//
// Inputs:
// origin 3d origin point of ray
// direction 3d (not necessarily normalized) direction vector of ray
// tnear start of ray segment
// tfar end of ray segment
// mask a 32 bit mask to identify active geometries.
// Output:
// hit information about hit
// Returns true if and only if there was a hit
bool intersect_ray(
const Eigen::RowVector3f& origin,
const Eigen::RowVector3f& direction,
Hit& hit,
float tnear = 0,
float tfar = std::numeric_limits<float>::infinity(),
int mask = 0xFFFFFFFF) const;
private:
// Initialize with a given mesh.
//
// Inputs:
// V #V by 3 list of vertex positions
// F #F by 3 list of Oriented triangles
// isStatic scene is optimized for static geometry
// Side effects:
// The first time this is ever called the embree engine is initialized.
void init(
const PointMatrixType& V,
const FaceMatrixType& F,
bool isStatic = false);
// Initialize embree with a given mesh.
//
// Inputs:
// V vector of #V by 3 list of vertex positions for each geometry
// F vector of #F by 3 list of Oriented triangles for each geometry
// masks a 32 bit mask to identify active geometries.
// isStatic scene is optimized for static geometry
// Side effects:
// The first time this is ever called the embree engine is initialized.
void init(
const std::vector<const PointMatrixType*>& V,
const std::vector<const FaceMatrixType*>& F,
const std::vector<int>& masks,
bool isStatic = false);
// Deinitialize embree datasctructures for current mesh. Also called on
// destruction: no need to call if you just want to init() once and
// destroy.
void deinit();
// initialize view parameters
void init_view();
// scene data
PointMatrixType V; // vertices
FaceMatrixType F; // faces
ColorMatrixType C; // colours
Eigen::RowVector3f uC; // uniform color
bool face_based;
bool uniform_color;
// Camera parameters
float camera_base_zoom;
float camera_zoom;
Eigen::Vector3f camera_base_translation;
Eigen::Vector3f camera_translation;
Eigen::Vector3f camera_eye;
Eigen::Vector3f camera_up;
Eigen::Vector3f camera_center;
float camera_view_angle;
float camera_dnear;
float camera_dfar;
// projection matrixes
Eigen::Matrix4f view;
Eigen::Matrix4f proj;
Eigen::Matrix4f norm;
Eigen::Matrix3f rot_matrix;
bool orthographic;
// embree data
RTCScene scene;
unsigned geomID;
bool initialized;
RTCDevice device;
void create_ray(
RTCRayHit& ray,
const Eigen::RowVector3f& origin,
const Eigen::RowVector3f& direction,
float tnear,
float tfar,
int mask) const;
};
}
}
#ifndef IGL_STATIC_LIBRARY
# include "EmbreeRenderer.cpp"
#endif
#endif //IGL_EMBREE_EMBREE_RENDERER_H
-1
View File
@@ -1027,7 +1027,6 @@ inline void Mesh::build_adjacencies()
inline bool Mesh::verify() //verifies connectivity of the mesh and prints some debug info
{
std::cout << std::endl;
// make sure that all vertices are mentioned at least once.
// though the loose vertex is not a bug, it most likely indicates that something is wrong with the mesh
std::vector<bool> map(m_vertices.size(), false);
+9
View File
@@ -0,0 +1,9 @@
#include "extension.h"
#include "pathinfo.h"
IGL_INLINE std::string igl::extension( const std::string & path)
{
std::string d,b,e,f;
pathinfo(path,d,b,e,f);
return e;
}
+29
View File
@@ -0,0 +1,29 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2020 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_EXTENSION_H
#define IGL_EXTENSION_H
#include "igl_inline.h"
#include <string>
namespace igl
{
// Inputs:
// path path with an extension (path/to/foo.obj)
// Returns extension without dot (obj)
//
// See also: pathinfo, basename, dirname
IGL_INLINE std::string extension( const std::string & path);
}
#ifndef IGL_STATIC_LIBRARY
# include "extension.cpp"
#endif
#endif
@@ -1,9 +1,9 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "extract_non_manifold_edge_curves.h"
#include <algorithm>
@@ -17,8 +17,8 @@ typename DerivedF,
typename DerivedEMAP,
typename uE2EType >
IGL_INLINE void igl::extract_non_manifold_edge_curves(
const Eigen::PlainObjectBase<DerivedF>& F,
const Eigen::PlainObjectBase<DerivedEMAP>& /*EMAP*/,
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedEMAP>& /*EMAP*/,
const std::vector<std::vector<uE2EType> >& uE2E,
std::vector<std::vector<size_t> >& curves) {
const size_t num_faces = F.rows();
@@ -1,9 +1,9 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
//
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
//
// This Source Code Form is subject to 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_NON_MANIFOLD_EDGE_CURVES
#define IGL_NON_MANIFOLD_EDGE_CURVES
@@ -34,8 +34,8 @@ namespace igl {
typename DerivedEMAP,
typename uE2EType>
IGL_INLINE void extract_non_manifold_edge_curves(
const Eigen::PlainObjectBase<DerivedF>& F,
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
const Eigen::MatrixBase<DerivedF>& F,
const Eigen::MatrixBase<DerivedEMAP>& EMAP,
const std::vector<std::vector<uE2EType> >& uE2E,
std::vector<std::vector<size_t> >& curves);
}
+3 -3
View File
@@ -14,7 +14,7 @@
#include <queue>
template <typename DerivedF, typename DerivedC>
IGL_INLINE void igl::facet_components(
IGL_INLINE int igl::facet_components(
const Eigen::MatrixBase<DerivedF> & F,
Eigen::PlainObjectBase<DerivedC> & C)
{
@@ -23,7 +23,7 @@ IGL_INLINE void igl::facet_components(
igl::facet_adjacency_matrix(F,A);
Eigen::Matrix<Index,Eigen::Dynamic,1> counts;
C = DerivedC::Zero(1,1);
connected_components(A,C,counts);
return connected_components(A,C,counts);
}
template <
@@ -91,7 +91,7 @@ IGL_INLINE void igl::facet_components(
// Explicit template instantiation
template void igl::facet_components<long, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(std::vector<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >, std::allocator<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
template void igl::facet_components<int, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(std::vector<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::allocator<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
template void igl::facet_components<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
template int igl::facet_components<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
#ifdef WIN32
template void igl::facet_components<__int64,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class std::vector<class std::vector<class std::vector<__int64,class std::allocator<__int64> >,class std::allocator<class std::vector<__int64,class std::allocator<__int64> > > >,class std::allocator<class std::vector<class std::vector<__int64,class std::allocator<__int64> >,class std::allocator<class std::vector<__int64,class std::allocator<__int64> > > > > > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &);
#endif
+1 -1
View File
@@ -21,7 +21,7 @@ namespace igl
// Outputs:
// C #F list of connected component ids
template <typename DerivedF, typename DerivedC>
IGL_INLINE void facet_components(
IGL_INLINE int facet_components(
const Eigen::MatrixBase<DerivedF> & F,
Eigen::PlainObjectBase<DerivedC> & C);

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