2
0
Эх сурвалжийг харах

Doxygen based documentation (#2233)

* basic config file

* documentation for two funcs

* better theme; subnamespace

* A-c

* documentation for all core headers

* more documentation

* documentation for all headers (except a few classes)

* rm accidental comment on igl

* just h

* typo

* accidental delete

* fix compile issues

* add main page [ci skip]
Alec Jacobson 2 жил өмнө
parent
commit
2cc372f70d
100 өөрчлөгдсөн 7206 нэмэгдсэн , 1650 устгасан
  1. 2530 0
      docs/doxygen-awesome.css
  2. 2728 0
      docs/doxygen.conf
  3. 21 0
      docs/index.md
  4. 160 119
      include/igl/AABB.h
  5. 12 15
      include/igl/ARAPEnergyType.h
  6. 32 20
      include/igl/AtA_cached.h
  7. 16 5
      include/igl/C_STR.h
  8. 7 4
      include/igl/Camera.h
  9. 6 2
      include/igl/EPS.h
  10. 1 1
      include/igl/FileEncoding.h
  11. 1 0
      include/igl/FileMemoryStream.h
  12. 48 44
      include/igl/HalfEdgeIterator.h
  13. 10 8
      include/igl/Hit.h
  14. 7 9
      include/igl/IndexComparison.h
  15. 34 25
      include/igl/LinSpaced.h
  16. 2 3
      include/igl/MappingEnergyType.h
  17. 7 0
      include/igl/MeshBooleanType.h
  18. 5 3
      include/igl/MshLoader.h
  19. 6 3
      include/igl/MshSaver.h
  20. 5 4
      include/igl/NormalType.h
  21. 3 3
      include/igl/ONE.h
  22. 2 0
      include/igl/PI.h
  23. 9 1
      include/igl/REDRUM.h
  24. 16 5
      include/igl/STR.h
  25. 5 3
      include/igl/SolverStatus.h
  26. 15 2
      include/igl/SortableRow.h
  27. 16 8
      include/igl/Timer.h
  28. 1 0
      include/igl/Viewport.h
  29. 10 1
      include/igl/WindingNumberAABB.h
  30. 4 3
      include/igl/WindingNumberMethod.h
  31. 3 4
      include/igl/WindingNumberTree.h
  32. 10 13
      include/igl/accumarray.h
  33. 47 42
      include/igl/active_set.h
  34. 24 18
      include/igl/adjacency_list.h
  35. 34 33
      include/igl/adjacency_matrix.h
  36. 9 10
      include/igl/all.h
  37. 10 15
      include/igl/all_pairs_distances.h
  38. 32 16
      include/igl/ambient_occlusion.h
  39. 6 7
      include/igl/angular_distance.h
  40. 9 10
      include/igl/any.h
  41. 8 7
      include/igl/any_of.h
  42. 51 40
      include/igl/arap.h
  43. 136 134
      include/igl/arap_dof.h
  44. 65 30
      include/igl/arap_linear_block.h
  45. 13 14
      include/igl/arap_rhs.h
  46. 9 10
      include/igl/average_from_edges_onto_vertices.h
  47. 5 7
      include/igl/average_onto_faces.h
  48. 6 9
      include/igl/average_onto_vertices.h
  49. 10 12
      include/igl/avg_edge_length.h
  50. 9 8
      include/igl/axis_angle_to_quat.h
  51. 6 8
      include/igl/barycenter.h
  52. 17 21
      include/igl/barycentric_coordinates.h
  53. 7 9
      include/igl/barycentric_interpolation.h
  54. 8 6
      include/igl/basename.h
  55. 27 28
      include/igl/bbw.h
  56. 19 22
      include/igl/bezier.h
  57. 21 12
      include/igl/bfs.h
  58. 6 11
      include/igl/bfs_orient.h
  59. 49 49
      include/igl/biharmonic_coordinates.h
  60. 27 31
      include/igl/bijective_composite_harmonic_mapping.h
  61. 10 9
      include/igl/blkdiag.h
  62. 14 16
      include/igl/blue_noise.h
  63. 4 7
      include/igl/bone_parents.h
  64. 24 25
      include/igl/boundary_conditions.h
  65. 21 12
      include/igl/boundary_facets.h
  66. 20 30
      include/igl/boundary_loop.h
  67. 8 7
      include/igl/bounding_box.h
  68. 5 6
      include/igl/bounding_box_diagonal.h
  69. 9 4
      include/igl/canonical_quaternions.h
  70. 42 39
      include/igl/cat.h
  71. 4 6
      include/igl/ceil.h
  72. 8 9
      include/igl/centroid.h
  73. 46 21
      include/igl/circulation.h
  74. 6 8
      include/igl/circumradius.h
  75. 86 65
      include/igl/collapse_edge.h
  76. 14 16
      include/igl/collapse_small_triangles.h
  77. 62 29
      include/igl/colon.h
  78. 38 23
      include/igl/colormap.h
  79. 5 7
      include/igl/column_to_quats.h
  80. 13 16
      include/igl/columnize.h
  81. 10 14
      include/igl/comb_cross_field.h
  82. 14 18
      include/igl/comb_frame_field.h
  83. 7 11
      include/igl/comb_line_field.h
  84. 20 19
      include/igl/combine.h
  85. 26 28
      include/igl/compute_frame_field_bisectors.h
  86. 23 19
      include/igl/connect_boundary_to_infinity.h
  87. 8 10
      include/igl/connected_components.h
  88. 14 6
      include/igl/copyleft/cgal/BinaryWindingNumberOperations.h
  89. 19 20
      include/igl/copyleft/cgal/CSGTree.h
  90. 9 10
      include/igl/copyleft/cgal/RemeshSelfIntersectionsParam.h
  91. 81 55
      include/igl/copyleft/cgal/SelfIntersectMesh.h
  92. 9 5
      include/igl/copyleft/cgal/assign.h
  93. 36 28
      include/igl/copyleft/cgal/assign_scalar.h
  94. 10 14
      include/igl/copyleft/cgal/cell_adjacency.h
  95. 23 20
      include/igl/copyleft/cgal/closest_facet.h
  96. 10 12
      include/igl/copyleft/cgal/complex_to_mesh.h
  97. 31 50
      include/igl/copyleft/cgal/component_inside_component.h
  98. 6 15
      include/igl/copyleft/cgal/convex_hull.h
  99. 4 5
      include/igl/copyleft/cgal/coplanar.h
  100. 5 9
      include/igl/copyleft/cgal/delaunay_triangulation.h

+ 2530 - 0
docs/doxygen-awesome.css

@@ -0,0 +1,2530 @@
+/**
+
+Doxygen Awesome
+https://github.com/jothepro/doxygen-awesome-css
+
+MIT License
+
+Copyright (c) 2021 - 2023 jothepro
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+*/
+
+html {
+    /* primary theme color. This will affect the entire websites color scheme: links, arrows, labels, ... */
+    --primary-color: #1779c4;
+    --primary-dark-color: #335c80;
+    --primary-light-color: #70b1e9;
+
+    /* page base colors */
+    --page-background-color: #ffffff;
+    --page-foreground-color: #2f4153;
+    --page-secondary-foreground-color: #6f7e8e;
+
+    /* color for all separators on the website: hr, borders, ... */
+    --separator-color: #dedede;
+
+    /* border radius for all rounded components. Will affect many components, like dropdowns, memitems, codeblocks, ... */
+    --border-radius-large: 8px;
+    --border-radius-small: 4px;
+    --border-radius-medium: 6px;
+
+    /* default spacings. Most components reference these values for spacing, to provide uniform spacing on the page. */
+    --spacing-small: 5px;
+    --spacing-medium: 10px;
+    --spacing-large: 16px;
+
+    /* default box shadow used for raising an element above the normal content. Used in dropdowns, search result, ... */
+    --box-shadow: 0 2px 8px 0 rgba(0,0,0,.075);
+
+    --odd-color: rgba(0,0,0,.028);
+
+    /* font-families. will affect all text on the website
+     * font-family: the normal font for text, headlines, menus
+     * font-family-monospace: used for preformatted text in memtitle, code, fragments
+     */
+    --font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;
+    --font-family-monospace: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;
+
+    /* font sizes */
+    --page-font-size: 15.6px;
+    --navigation-font-size: 14.4px;
+    --toc-font-size: 13.4px;
+    --code-font-size: 14px; /* affects code, fragment */
+    --title-font-size: 22px;
+
+    /* content text properties. These only affect the page content, not the navigation or any other ui elements */
+    --content-line-height: 27px;
+    /* The content is centered and constraint in it's width. To make the content fill the whole page, set the variable to auto.*/
+    --content-maxwidth: 1050px;
+    --table-line-height: 24px;
+    --toc-sticky-top: var(--spacing-medium);
+    --toc-width: 200px;
+    --toc-max-height: calc(100vh - 2 * var(--spacing-medium) - 85px);
+
+    /* colors for various content boxes: @warning, @note, @deprecated @bug */
+    --warning-color: #f8d1cc;
+    --warning-color-dark: #b61825;
+    --warning-color-darker: #75070f;
+    --note-color: #faf3d8;
+    --note-color-dark: #f3a600;
+    --note-color-darker: #5f4204;
+    --todo-color: #e4f3ff;
+    --todo-color-dark: #1879C4;
+    --todo-color-darker: #274a5c;
+    --deprecated-color: #ecf0f3;
+    --deprecated-color-dark: #5b6269;
+    --deprecated-color-darker: #43454a;
+    --bug-color: #e4dafd;
+    --bug-color-dark: #5b2bdd;
+    --bug-color-darker: #2a0d72;
+    --invariant-color: #d8f1e3;
+    --invariant-color-dark: #44b86f;
+    --invariant-color-darker: #265532;
+
+    /* blockquote colors */
+    --blockquote-background: #f8f9fa;
+    --blockquote-foreground: #636568;
+
+    /* table colors */
+    --tablehead-background: #f1f1f1;
+    --tablehead-foreground: var(--page-foreground-color);
+
+    /* menu-display: block | none
+     * Visibility of the top navigation on screens >= 768px. On smaller screen the menu is always visible.
+     * `GENERATE_TREEVIEW` MUST be enabled!
+     */
+    --menu-display: block;
+
+    --menu-focus-foreground: var(--page-background-color);
+    --menu-focus-background: var(--primary-color);
+    --menu-selected-background: rgba(0,0,0,.05);
+
+
+    --header-background: var(--page-background-color);
+    --header-foreground: var(--page-foreground-color);
+
+    /* searchbar colors */
+    --searchbar-background: var(--side-nav-background);
+    --searchbar-foreground: var(--page-foreground-color);
+
+    /* searchbar size
+     * (`searchbar-width` is only applied on screens >= 768px.
+     * on smaller screens the searchbar will always fill the entire screen width) */
+    --searchbar-height: 33px;
+    --searchbar-width: 210px;
+    --searchbar-border-radius: var(--searchbar-height);
+
+    /* code block colors */
+    --code-background: #f5f5f5;
+    --code-foreground: var(--page-foreground-color);
+
+    /* fragment colors */
+    --fragment-background: #F8F9FA;
+    --fragment-foreground: #37474F;
+    --fragment-keyword: #bb6bb2;
+    --fragment-keywordtype: #8258b3;
+    --fragment-keywordflow: #d67c3b;
+    --fragment-token: #438a59;
+    --fragment-comment: #969696;
+    --fragment-link: #5383d6;
+    --fragment-preprocessor: #46aaa5;
+    --fragment-linenumber-color: #797979;
+    --fragment-linenumber-background: #f4f4f5;
+    --fragment-linenumber-border: #e3e5e7;
+    --fragment-lineheight: 20px;
+
+    /* sidebar navigation (treeview) colors */
+    --side-nav-background: #fbfbfb;
+    --side-nav-foreground: var(--page-foreground-color);
+    --side-nav-arrow-opacity: 0;
+    --side-nav-arrow-hover-opacity: 0.9;
+
+    --toc-background: var(--side-nav-background);
+    --toc-foreground: var(--side-nav-foreground);
+
+    /* height of an item in any tree / collapsible table */
+    --tree-item-height: 30px;
+
+    --memname-font-size: var(--code-font-size);
+    --memtitle-font-size: 18px;
+
+    --webkit-scrollbar-size: 7px;
+    --webkit-scrollbar-padding: 4px;
+    --webkit-scrollbar-color: var(--separator-color);
+}
+
+@media screen and (max-width: 767px) {
+    html {
+        --page-font-size: 16px;
+        --navigation-font-size: 16px;
+        --toc-font-size: 15px;
+        --code-font-size: 15px; /* affects code, fragment */
+        --title-font-size: 22px;
+    }
+}
+
+@media (prefers-color-scheme: dark) {
+    html:not(.light-mode) {
+        color-scheme: dark;
+
+        --primary-color: #1982d2;
+        --primary-dark-color: #86a9c4;
+        --primary-light-color: #4779ac;
+
+        --box-shadow: 0 2px 8px 0 rgba(0,0,0,.35);
+
+        --odd-color: rgba(100,100,100,.06);
+
+        --menu-selected-background: rgba(0,0,0,.4);
+
+        --page-background-color: #1C1D1F;
+        --page-foreground-color: #d2dbde;
+        --page-secondary-foreground-color: #859399;
+        --separator-color: #38393b;
+        --side-nav-background: #252628;
+
+        --code-background: #2a2c2f;
+
+        --tablehead-background: #2a2c2f;
+    
+        --blockquote-background: #222325;
+        --blockquote-foreground: #7e8c92;
+
+        --warning-color: #2e1917;
+        --warning-color-dark: #ad2617;
+        --warning-color-darker: #f5b1aa;
+        --note-color: #3b2e04;
+        --note-color-dark: #f1b602;
+        --note-color-darker: #ceb670;
+        --todo-color: #163750;
+        --todo-color-dark: #1982D2;
+        --todo-color-darker: #dcf0fa;
+        --deprecated-color: #2e323b;
+        --deprecated-color-dark: #738396;
+        --deprecated-color-darker: #abb0bd;
+        --bug-color: #2a2536;
+        --bug-color-dark: #7661b3;
+        --bug-color-darker: #ae9ed6;
+        --invariant-color: #303a35;
+        --invariant-color-dark: #76ce96;
+        --invariant-color-darker: #cceed5;
+
+        --fragment-background: #282c34;
+        --fragment-foreground: #dbe4eb;
+        --fragment-keyword: #cc99cd;
+        --fragment-keywordtype: #ab99cd;
+        --fragment-keywordflow: #e08000;
+        --fragment-token: #7ec699;
+        --fragment-comment: #999999;
+        --fragment-link: #98c0e3;
+        --fragment-preprocessor: #65cabe;
+        --fragment-linenumber-color: #cccccc;
+        --fragment-linenumber-background: #35393c;
+        --fragment-linenumber-border: #1f1f1f;
+    }
+}
+
+/* dark mode variables are defined twice, to support both the dark-mode without and with doxygen-awesome-darkmode-toggle.js */
+html.dark-mode {
+    color-scheme: dark;
+
+    --primary-color: #1982d2;
+    --primary-dark-color: #86a9c4;
+    --primary-light-color: #4779ac;
+
+    --box-shadow: 0 2px 8px 0 rgba(0,0,0,.30);
+
+    --odd-color: rgba(100,100,100,.06);
+
+    --menu-selected-background: rgba(0,0,0,.4);
+
+    --page-background-color: #1C1D1F;
+    --page-foreground-color: #d2dbde;
+    --page-secondary-foreground-color: #859399;
+    --separator-color: #38393b;
+    --side-nav-background: #252628;
+
+    --code-background: #2a2c2f;
+
+    --tablehead-background: #2a2c2f;
+
+    --blockquote-background: #222325;
+    --blockquote-foreground: #7e8c92;
+
+    --warning-color: #2e1917;
+    --warning-color-dark: #ad2617;
+    --warning-color-darker: #f5b1aa;
+    --note-color: #3b2e04;
+    --note-color-dark: #f1b602;
+    --note-color-darker: #ceb670;
+    --todo-color: #163750;
+    --todo-color-dark: #1982D2;
+    --todo-color-darker: #dcf0fa;
+    --deprecated-color: #2e323b;
+    --deprecated-color-dark: #738396;
+    --deprecated-color-darker: #abb0bd;
+    --bug-color: #2a2536;
+    --bug-color-dark: #7661b3;
+    --bug-color-darker: #ae9ed6;
+    --invariant-color: #303a35;
+    --invariant-color-dark: #76ce96;
+    --invariant-color-darker: #cceed5;
+
+    --fragment-background: #282c34;
+    --fragment-foreground: #dbe4eb;
+    --fragment-keyword: #cc99cd;
+    --fragment-keywordtype: #ab99cd;
+    --fragment-keywordflow: #e08000;
+    --fragment-token: #7ec699;
+    --fragment-comment: #999999;
+    --fragment-link: #98c0e3;
+    --fragment-preprocessor: #65cabe;
+    --fragment-linenumber-color: #cccccc;
+    --fragment-linenumber-background: #35393c;
+    --fragment-linenumber-border: #1f1f1f;
+}
+
+body {
+    color: var(--page-foreground-color);
+    background-color: var(--page-background-color);
+    font-size: var(--page-font-size);
+}
+
+body, table, div, p, dl, #nav-tree .label, .title,
+.sm-dox a, .sm-dox a:hover, .sm-dox a:focus, #projectname,
+.SelectItem, #MSearchField, .navpath li.navelem a,
+.navpath li.navelem a:hover, p.reference, p.definition {
+    font-family: var(--font-family);
+}
+
+h1, h2, h3, h4, h5 {
+    margin-top: .9em;
+    font-weight: 600;
+    line-height: initial;
+}
+
+p, div, table, dl, p.reference, p.definition {
+    font-size: var(--page-font-size);
+}
+
+p.reference, p.definition {
+    color: var(--page-secondary-foreground-color);
+}
+
+a:link, a:visited, a:hover, a:focus, a:active {
+    color: var(--primary-color) !important;
+    font-weight: 500;
+}
+
+a.anchor {
+    scroll-margin-top: var(--spacing-large);
+    display: block;
+}
+
+/*
+ Title and top navigation
+ */
+
+#top {
+    background: var(--header-background);
+    border-bottom: 1px solid var(--separator-color);
+}
+
+@media screen and (min-width: 768px) {
+    #top {
+        display: flex;
+        flex-wrap: wrap;
+        justify-content: space-between;
+        align-items: center;
+    }
+}
+
+#main-nav {
+    flex-grow: 5;
+    padding: var(--spacing-small) var(--spacing-medium);
+}
+
+#titlearea {
+    width: auto;
+    padding: var(--spacing-medium) var(--spacing-large);
+    background: none;
+    color: var(--header-foreground);
+    border-bottom: none;
+}
+
+@media screen and (max-width: 767px) {
+    #titlearea {
+        padding-bottom: var(--spacing-small);
+    }
+}
+
+#titlearea table tbody tr {
+    height: auto !important;
+}
+
+#projectname {
+    font-size: var(--title-font-size);
+    font-weight: 600;
+}
+
+#projectnumber {
+    font-family: inherit;
+    font-size: 60%;
+}
+
+#projectbrief {
+    font-family: inherit;
+    font-size: 80%;
+}
+
+#projectlogo {
+    vertical-align: middle;
+}
+
+#projectlogo img {
+    max-height: calc(var(--title-font-size) * 2);
+    margin-right: var(--spacing-small);
+}
+
+.sm-dox, .tabs, .tabs2, .tabs3 {
+    background: none;
+    padding: 0;
+}
+
+.tabs, .tabs2, .tabs3 {
+    border-bottom: 1px solid var(--separator-color);
+    margin-bottom: -1px;
+}
+
+.main-menu-btn-icon, .main-menu-btn-icon:before, .main-menu-btn-icon:after {
+    background: var(--page-secondary-foreground-color);
+}
+
+@media screen and (max-width: 767px) {
+    .sm-dox a span.sub-arrow {
+        background: var(--code-background);
+    }
+
+    #main-menu a.has-submenu span.sub-arrow {
+        color: var(--page-secondary-foreground-color);
+        border-radius: var(--border-radius-medium);
+    }
+
+    #main-menu a.has-submenu:hover span.sub-arrow {
+        color: var(--page-foreground-color);
+    }
+}
+
+@media screen and (min-width: 768px) {
+    .sm-dox li, .tablist li {
+        display: var(--menu-display);
+    }
+
+    .sm-dox a span.sub-arrow {
+        border-color: var(--header-foreground) transparent transparent transparent;
+    }
+
+    .sm-dox a:hover span.sub-arrow {
+        border-color: var(--menu-focus-foreground) transparent transparent transparent;
+    }
+
+    .sm-dox ul a span.sub-arrow {
+        border-color: transparent transparent transparent var(--page-foreground-color);
+    }
+
+    .sm-dox ul a:hover span.sub-arrow {
+        border-color: transparent transparent transparent var(--menu-focus-foreground);
+    }
+}
+
+.sm-dox ul {
+    background: var(--page-background-color);
+    box-shadow: var(--box-shadow);
+    border: 1px solid var(--separator-color);
+    border-radius: var(--border-radius-medium) !important;
+    padding: var(--spacing-small);
+    animation: ease-out 150ms slideInMenu;
+}
+
+@keyframes slideInMenu {
+    from {
+        opacity: 0;
+        transform: translate(0px, -2px);
+    }
+
+    to {
+        opacity: 1;
+        transform: translate(0px, 0px);
+    }
+}
+
+.sm-dox ul a {
+    color: var(--page-foreground-color) !important;
+    background: var(--page-background-color);
+    font-size: var(--navigation-font-size);
+}
+
+.sm-dox>li>ul:after {
+    border-bottom-color: var(--page-background-color) !important;
+}
+
+.sm-dox>li>ul:before {
+    border-bottom-color: var(--separator-color) !important;
+}
+
+.sm-dox ul a:hover, .sm-dox ul a:active, .sm-dox ul a:focus {
+    font-size: var(--navigation-font-size) !important;
+    color: var(--menu-focus-foreground) !important;
+    text-shadow: none;
+    background-color: var(--menu-focus-background);
+    border-radius: var(--border-radius-small) !important;
+}
+
+.sm-dox a, .sm-dox a:focus, .tablist li, .tablist li a, .tablist li.current a {
+    text-shadow: none;
+    background: transparent;
+    background-image: none !important;
+    color: var(--header-foreground) !important;
+    font-weight: normal;
+    font-size: var(--navigation-font-size);
+    border-radius: var(--border-radius-small) !important;
+}
+
+.sm-dox a:focus {
+    outline: auto;
+}
+
+.sm-dox a:hover, .sm-dox a:active, .tablist li a:hover {
+    text-shadow: none;
+    font-weight: normal;
+    background: var(--menu-focus-background);
+    color: var(--menu-focus-foreground) !important;
+    border-radius: var(--border-radius-small) !important;
+    font-size: var(--navigation-font-size);
+}
+
+.tablist li.current {
+    border-radius: var(--border-radius-small);
+    background: var(--menu-selected-background);
+}
+
+.tablist li {
+    margin: var(--spacing-small) 0 var(--spacing-small) var(--spacing-small);
+}
+
+.tablist a {
+    padding: 0 var(--spacing-large);
+}
+
+
+/*
+ Search box
+ */
+
+#MSearchBox {
+    height: var(--searchbar-height);
+    background: var(--searchbar-background);
+    border-radius: var(--searchbar-border-radius);
+    border: 1px solid var(--separator-color);
+    overflow: hidden;
+    width: var(--searchbar-width);
+    position: relative;
+    box-shadow: none;
+    display: block;
+    margin-top: 0;
+}
+
+/* until Doxygen 1.9.4 */
+.left img#MSearchSelect {
+    left: 0;
+    user-select: none;
+    padding-left: 8px;
+}
+
+/* Doxygen 1.9.5 */
+.left span#MSearchSelect {
+    left: 0;
+    user-select: none;
+    margin-left: 8px;
+    padding: 0;
+}
+
+.left #MSearchSelect[src$=".png"] {
+    padding-left: 0
+}
+
+.SelectionMark {
+    user-select: none;
+}
+
+.tabs .left #MSearchSelect {
+    padding-left: 0;
+}
+
+.tabs #MSearchBox {
+    position: absolute;
+    right: var(--spacing-medium);
+}
+
+@media screen and (max-width: 767px) {
+    .tabs #MSearchBox {
+        position: relative;
+        right: 0;
+        margin-left: var(--spacing-medium);
+        margin-top: 0;
+    }
+}
+
+#MSearchSelectWindow, #MSearchResultsWindow {
+    z-index: 9999;
+}
+
+#MSearchBox.MSearchBoxActive {
+    border-color: var(--primary-color);
+    box-shadow: inset 0 0 0 1px var(--primary-color);
+}
+
+#main-menu > li:last-child {
+    margin-right: 0;
+}
+
+@media screen and (max-width: 767px) {
+    #main-menu > li:last-child {
+        height: 50px;
+    }
+}
+
+#MSearchField {
+    font-size: var(--navigation-font-size);
+    height: calc(var(--searchbar-height) - 2px);
+    background: transparent;
+    width: calc(var(--searchbar-width) - 64px);
+}
+
+.MSearchBoxActive #MSearchField {
+    color: var(--searchbar-foreground);
+}
+
+#MSearchSelect {
+    top: calc(calc(var(--searchbar-height) / 2) - 11px);
+}
+
+#MSearchBox span.left, #MSearchBox span.right {
+    background: none;
+    background-image: none;
+}
+
+#MSearchBox span.right {
+    padding-top: calc(calc(var(--searchbar-height) / 2) - 12px);
+    position: absolute;
+    right: var(--spacing-small);
+}
+
+.tabs #MSearchBox span.right {
+    top: calc(calc(var(--searchbar-height) / 2) - 12px);
+}
+
+@keyframes slideInSearchResults {
+    from {
+        opacity: 0;
+        transform: translate(0, 15px);
+    }
+
+    to {
+        opacity: 1;
+        transform: translate(0, 20px);
+    }
+}
+
+#MSearchResultsWindow {
+    left: auto !important;
+    right: var(--spacing-medium);
+    border-radius: var(--border-radius-large);
+    border: 1px solid var(--separator-color);
+    transform: translate(0, 20px);
+    box-shadow: var(--box-shadow);
+    animation: ease-out 280ms slideInSearchResults;
+    background: var(--page-background-color);
+}
+
+iframe#MSearchResults {
+    margin: 4px;
+}
+
+iframe {
+    color-scheme: normal;
+}
+
+@media (prefers-color-scheme: dark) {
+    html:not(.light-mode) iframe#MSearchResults {
+        filter: invert() hue-rotate(180deg);
+    }
+}
+
+html.dark-mode iframe#MSearchResults {
+    filter: invert() hue-rotate(180deg);
+}
+
+#MSearchResults .SRPage {
+    background-color: transparent;
+}
+
+#MSearchResults .SRPage .SREntry {
+    font-size: 10pt;
+    padding: var(--spacing-small) var(--spacing-medium);
+}
+
+#MSearchSelectWindow {
+    border: 1px solid var(--separator-color);
+    border-radius: var(--border-radius-medium);
+    box-shadow: var(--box-shadow);
+    background: var(--page-background-color);
+    padding-top: var(--spacing-small);
+    padding-bottom: var(--spacing-small);
+}
+
+#MSearchSelectWindow a.SelectItem {
+    font-size: var(--navigation-font-size);
+    line-height: var(--content-line-height);
+    margin: 0 var(--spacing-small);
+    border-radius: var(--border-radius-small);
+    color: var(--page-foreground-color) !important;
+    font-weight: normal;
+}
+
+#MSearchSelectWindow a.SelectItem:hover {
+    background: var(--menu-focus-background);
+    color: var(--menu-focus-foreground) !important;
+}
+
+@media screen and (max-width: 767px) {
+    #MSearchBox {
+        margin-top: var(--spacing-medium);
+        margin-bottom: var(--spacing-medium);
+        width: calc(100vw - 30px);
+    }
+
+    #main-menu > li:last-child {
+        float: none !important;
+    }
+
+    #MSearchField {
+        width: calc(100vw - 110px);
+    }
+
+    @keyframes slideInSearchResultsMobile {
+        from {
+            opacity: 0;
+            transform: translate(0, 15px);
+        }
+
+        to {
+            opacity: 1;
+            transform: translate(0, 20px);
+        }
+    }
+
+    #MSearchResultsWindow {
+        left: var(--spacing-medium) !important;
+        right: var(--spacing-medium);
+        overflow: auto;
+        transform: translate(0, 20px);
+        animation: ease-out 280ms slideInSearchResultsMobile;
+        width: auto !important;
+    }
+
+    /*
+     * Overwrites for fixing the searchbox on mobile in doxygen 1.9.2
+     */
+    label.main-menu-btn ~ #searchBoxPos1 {
+        top: 3px !important;
+        right: 6px !important;
+        left: 45px;
+        display: flex;
+    }
+
+    label.main-menu-btn ~ #searchBoxPos1 > #MSearchBox {
+        margin-top: 0;
+        margin-bottom: 0;
+        flex-grow: 2;
+        float: left;
+    }
+}
+
+/*
+ Tree view
+ */
+
+#side-nav {
+    padding: 0 !important;
+    background: var(--side-nav-background);
+    min-width: 8px;
+    max-width: 50vw;
+}
+
+@media screen and (max-width: 767px) {
+    #side-nav {
+        display: none;
+    }
+
+    #doc-content {
+        margin-left: 0 !important;
+    }
+}
+
+#nav-tree {
+    background: transparent;
+    margin-right: 1px;
+}
+
+#nav-tree .label {
+    font-size: var(--navigation-font-size);
+}
+
+#nav-tree .item {
+    height: var(--tree-item-height);
+    line-height: var(--tree-item-height);
+}
+
+#nav-sync {
+    bottom: 12px;
+    right: 12px;
+    top: auto !important;
+    user-select: none;
+}
+
+#nav-tree .selected {
+    text-shadow: none;
+    background-image: none;
+    background-color: transparent;
+    position: relative;
+}
+
+#nav-tree .selected::after {
+    content: "";
+    position: absolute;
+    top: 1px;
+    bottom: 1px;
+    left: 0;
+    width: 4px;
+    border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0;
+    background: var(--primary-color);
+}
+
+
+#nav-tree a {
+    color: var(--side-nav-foreground) !important;
+    font-weight: normal;
+}
+
+#nav-tree a:focus {
+    outline-style: auto;
+}
+
+#nav-tree .arrow {
+    opacity: var(--side-nav-arrow-opacity);
+}
+
+.arrow {
+    color: inherit;
+    cursor: pointer;
+    font-size: 45%;
+    vertical-align: middle;
+    margin-right: 2px;
+    font-family: serif;
+    height: auto;
+    text-align: right;
+}
+
+#nav-tree div.item:hover .arrow, #nav-tree a:focus .arrow {
+    opacity: var(--side-nav-arrow-hover-opacity);
+}
+
+#nav-tree .selected a {
+    color: var(--primary-color) !important;
+    font-weight: bolder;
+    font-weight: 600;
+}
+
+.ui-resizable-e {
+    width: 4px;
+    background: transparent;
+    box-shadow: inset -1px 0 0 0 var(--separator-color);
+}
+
+/*
+ Contents
+ */
+
+div.header {
+    border-bottom: 1px solid var(--separator-color);
+    background-color: var(--page-background-color);
+    background-image: none;
+}
+
+@media screen and (min-width: 1000px) {
+    #doc-content > div > div.contents,
+    .PageDoc > div.contents {
+        display: flex;
+        flex-direction: row-reverse;
+        flex-wrap: nowrap;
+        align-items: flex-start;
+    }
+    
+    div.contents .textblock {
+        min-width: 200px;
+        flex-grow: 1;
+    }
+}
+
+div.contents, div.header .title, div.header .summary {
+    max-width: var(--content-maxwidth);
+}
+
+div.contents, div.header .title  {
+    line-height: initial;
+    margin: calc(var(--spacing-medium) + .2em) auto var(--spacing-medium) auto;
+}
+
+div.header .summary {
+    margin: var(--spacing-medium) auto 0 auto;
+}
+
+div.headertitle {
+    padding: 0;
+}
+
+div.header .title {
+    font-weight: 600;
+    font-size: 225%;
+    padding: var(--spacing-medium) var(--spacing-large);
+    word-break: break-word;
+}
+
+div.header .summary {
+    width: auto;
+    display: block;
+    float: none;
+    padding: 0 var(--spacing-large);
+}
+
+td.memSeparator {
+    border-color: var(--separator-color);
+}
+
+span.mlabel {
+    background: var(--primary-color);
+    border: none;
+    padding: 4px 9px;
+    border-radius: 12px;
+    margin-right: var(--spacing-medium);
+}
+
+span.mlabel:last-of-type {
+    margin-right: 2px;
+}
+
+div.contents {
+    padding: 0 var(--spacing-large);
+}
+
+div.contents p, div.contents li {
+    line-height: var(--content-line-height);
+}
+
+div.contents div.dyncontent {
+    margin: var(--spacing-medium) 0;
+}
+
+@media (prefers-color-scheme: dark) {
+    html:not(.light-mode) div.contents div.dyncontent img,
+    html:not(.light-mode) div.contents center img,
+    html:not(.light-mode) div.contents > table img,
+    html:not(.light-mode) div.contents div.dyncontent iframe,
+    html:not(.light-mode) div.contents center iframe,
+    html:not(.light-mode) div.contents table iframe,
+    html:not(.light-mode) div.contents .dotgraph iframe {
+        filter: brightness(89%) hue-rotate(180deg) invert();
+    }
+}
+
+html.dark-mode div.contents div.dyncontent img,
+html.dark-mode div.contents center img,
+html.dark-mode div.contents > table img,
+html.dark-mode div.contents div.dyncontent iframe,
+html.dark-mode div.contents center iframe,
+html.dark-mode div.contents table iframe,
+html.dark-mode div.contents .dotgraph iframe
+ {
+    filter: brightness(89%) hue-rotate(180deg) invert();
+}
+
+h2.groupheader {
+    border-bottom: 0px;
+    color: var(--page-foreground-color);
+    box-shadow: 
+        100px 0 var(--page-background-color), 
+        -100px 0 var(--page-background-color),
+        100px 0.75px var(--separator-color),
+        -100px 0.75px var(--separator-color),
+        500px 0 var(--page-background-color), 
+        -500px 0 var(--page-background-color),
+        500px 0.75px var(--separator-color),
+        -500px 0.75px var(--separator-color),
+        900px 0 var(--page-background-color), 
+        -900px 0 var(--page-background-color),
+        900px 0.75px var(--separator-color),
+        -900px 0.75px var(--separator-color),
+        1400px 0 var(--page-background-color),
+        -1400px 0 var(--page-background-color), 
+        1400px 0.75px var(--separator-color),
+        -1400px 0.75px var(--separator-color),
+        1900px 0 var(--page-background-color),
+        -1900px 0 var(--page-background-color),
+        1900px 0.75px var(--separator-color),
+        -1900px 0.75px var(--separator-color);
+}
+
+blockquote {
+    margin: 0 var(--spacing-medium) 0 var(--spacing-medium);
+    padding: var(--spacing-small) var(--spacing-large);
+    background: var(--blockquote-background);
+    color: var(--blockquote-foreground);
+    border-left: 0;
+    overflow: visible;
+    border-radius: var(--border-radius-medium);
+    overflow: visible;
+    position: relative;
+}
+
+blockquote::before, blockquote::after {
+    font-weight: bold;
+    font-family: serif;
+    font-size: 360%;
+    opacity: .15;
+    position: absolute;
+}
+
+blockquote::before {
+    content: "“";
+    left: -10px;
+    top: 4px;
+}
+
+blockquote::after {
+    content: "”";
+    right: -8px;
+    bottom: -25px;
+}
+
+blockquote p {
+    margin: var(--spacing-small) 0 var(--spacing-medium) 0;
+}
+.paramname {
+    font-weight: 600;
+    color: var(--primary-dark-color);
+}
+
+.paramname > code {
+    border: 0;
+}
+
+table.params .paramname {
+    font-weight: 600;
+    font-family: var(--font-family-monospace);
+    font-size: var(--code-font-size);
+    padding-right: var(--spacing-small);
+    line-height: var(--table-line-height);
+}
+
+h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow {
+    text-shadow: 0 0 15px var(--primary-light-color);
+}
+
+.alphachar a {
+    color: var(--page-foreground-color);
+}
+
+.dotgraph {
+    max-width: 100%;
+    overflow-x: scroll;
+}
+
+.dotgraph .caption {
+    position: sticky;
+    left: 0;
+}
+
+/* Wrap Graphviz graphs with the `interactive_dotgraph` class if `INTERACTIVE_SVG = YES` */
+.interactive_dotgraph .dotgraph iframe {
+    max-width: 100%;
+}
+
+/*
+ Table of Contents
+ */
+
+div.contents .toc {
+    max-height: var(--toc-max-height);
+    min-width: var(--toc-width);
+    border: 0;
+    border-left: 1px solid var(--separator-color);
+    border-radius: 0;
+    background-color: transparent;
+    box-shadow: none;
+    position: sticky;
+    top: var(--toc-sticky-top);
+    padding: 0 var(--spacing-large);
+    margin: var(--spacing-small) 0 var(--spacing-large) var(--spacing-large);
+}
+
+div.toc h3 {
+    color: var(--toc-foreground);
+    font-size: var(--navigation-font-size);
+    margin: var(--spacing-large) 0 var(--spacing-medium) 0;
+}
+
+div.toc li {
+    padding: 0;
+    background: none;
+    line-height: var(--toc-font-size);
+    margin: var(--toc-font-size) 0 0 0;
+}
+
+div.toc li::before {
+    display: none;
+}
+
+div.toc ul {
+    margin-top: 0
+}
+
+div.toc li a {
+    font-size: var(--toc-font-size);
+    color: var(--page-foreground-color) !important;
+    text-decoration: none;
+}
+
+div.toc li a:hover, div.toc li a.active {
+    color: var(--primary-color) !important;
+}
+
+div.toc li a.aboveActive {
+    color: var(--page-secondary-foreground-color) !important;
+}
+
+
+@media screen and (max-width: 999px) {
+    div.contents .toc {
+        max-height: 45vh;
+        float: none;
+        width: auto;
+        margin: 0 0 var(--spacing-medium) 0;
+        position: relative;
+        top: 0;
+        position: relative;
+        border: 1px solid var(--separator-color);
+        border-radius: var(--border-radius-medium);
+        background-color: var(--toc-background);
+        box-shadow: var(--box-shadow);
+    }
+
+    div.contents .toc.interactive {
+        max-height: calc(var(--navigation-font-size) + 2 * var(--spacing-large));
+        overflow: hidden;
+    }
+
+    div.contents .toc > h3 {
+        -webkit-tap-highlight-color: transparent;
+        cursor: pointer;
+        position: sticky;
+        top: 0;
+        background-color: var(--toc-background);
+        margin: 0;
+        padding: var(--spacing-large) 0;
+        display: block;
+    }
+
+    div.contents .toc.interactive > h3::before {
+        content: "";
+        width: 0; 
+        height: 0; 
+        border-left: 4px solid transparent;
+        border-right: 4px solid transparent;
+        border-top: 5px solid var(--primary-color);
+        display: inline-block;
+        margin-right: var(--spacing-small);
+        margin-bottom: calc(var(--navigation-font-size) / 4);
+        transform: rotate(-90deg);
+        transition: transform 0.25s ease-out;
+    }
+
+    div.contents .toc.interactive.open > h3::before {
+        transform: rotate(0deg);
+    }
+
+    div.contents .toc.interactive.open {
+        max-height: 45vh;
+        overflow: auto;
+        transition: max-height 0.2s ease-in-out;
+    }
+
+    div.contents .toc a, div.contents .toc a.active {
+        color: var(--primary-color) !important;
+    }
+
+    div.contents .toc a:hover {
+        text-decoration: underline;
+    }
+}
+
+/*
+ Code & Fragments
+ */
+
+code, div.fragment, pre.fragment {
+    border-radius: var(--border-radius-small);
+    border: 1px solid var(--separator-color);
+    overflow: hidden;
+}
+
+code {
+    display: inline;
+    background: var(--code-background);
+    color: var(--code-foreground);
+    padding: 2px 6px;
+}
+
+div.fragment, pre.fragment {
+    margin: var(--spacing-medium) 0;
+    padding: calc(var(--spacing-large) - (var(--spacing-large) / 6)) var(--spacing-large);
+    background: var(--fragment-background);
+    color: var(--fragment-foreground);
+    overflow-x: auto;
+}
+
+@media screen and (max-width: 767px) {
+    div.fragment, pre.fragment {
+        border-top-right-radius: 0;
+        border-bottom-right-radius: 0;
+        border-right: 0;
+    }
+
+    .contents > div.fragment,
+    .textblock > div.fragment,
+    .textblock > pre.fragment,
+    .contents > .doxygen-awesome-fragment-wrapper > div.fragment,
+    .textblock > .doxygen-awesome-fragment-wrapper > div.fragment,
+    .textblock > .doxygen-awesome-fragment-wrapper > pre.fragment {
+        margin: var(--spacing-medium) calc(0px - var(--spacing-large));
+        border-radius: 0;
+        border-left: 0;
+    }
+
+    .textblock li > .fragment,
+    .textblock li > .doxygen-awesome-fragment-wrapper > .fragment {
+        margin: var(--spacing-medium) calc(0px - var(--spacing-large));
+    }
+
+    .memdoc li > .fragment,
+    .memdoc li > .doxygen-awesome-fragment-wrapper > .fragment {
+        margin: var(--spacing-medium) calc(0px - var(--spacing-medium));
+    }
+
+    .textblock ul, .memdoc ul {
+        overflow: initial;
+    }
+
+    .memdoc > div.fragment,
+    .memdoc > pre.fragment,
+    dl dd > div.fragment,
+    dl dd pre.fragment,
+    .memdoc > .doxygen-awesome-fragment-wrapper > div.fragment,
+    .memdoc > .doxygen-awesome-fragment-wrapper > pre.fragment,
+    dl dd > .doxygen-awesome-fragment-wrapper > div.fragment,
+    dl dd .doxygen-awesome-fragment-wrapper > pre.fragment {
+        margin: var(--spacing-medium) calc(0px - var(--spacing-medium));
+        border-radius: 0;
+        border-left: 0;
+    }
+}
+
+code, code a, pre.fragment, div.fragment, div.fragment .line, div.fragment span, div.fragment .line a, div.fragment .line span {
+    font-family: var(--font-family-monospace);
+    font-size: var(--code-font-size) !important;
+}
+
+div.line:after {
+    margin-right: var(--spacing-medium);
+}
+
+div.fragment .line, pre.fragment {
+    white-space: pre;
+    word-wrap: initial;
+    line-height: var(--fragment-lineheight);
+}
+
+div.fragment span.keyword {
+    color: var(--fragment-keyword);
+}
+
+div.fragment span.keywordtype {
+    color: var(--fragment-keywordtype);
+}
+
+div.fragment span.keywordflow {
+    color: var(--fragment-keywordflow);
+}
+
+div.fragment span.stringliteral {
+    color: var(--fragment-token)
+}
+
+div.fragment span.comment {
+    color: var(--fragment-comment);
+}
+
+div.fragment a.code {
+    color: var(--fragment-link) !important;
+}
+
+div.fragment span.preprocessor {
+    color: var(--fragment-preprocessor);
+}
+
+div.fragment span.lineno {
+    display: inline-block;
+    width: 27px;
+    border-right: none;
+    background: var(--fragment-linenumber-background);
+    color: var(--fragment-linenumber-color);
+}
+
+div.fragment span.lineno a {
+    background: none;
+    color: var(--fragment-link) !important;
+}
+
+div.fragment .line:first-child .lineno {
+    box-shadow: -999999px 0px 0 999999px var(--fragment-linenumber-background), -999998px 0px 0 999999px var(--fragment-linenumber-border);
+}
+
+div.line {
+    border-radius: var(--border-radius-small);
+}
+
+div.line.glow {
+    background-color: var(--primary-light-color);
+    box-shadow: none;
+}
+
+/*
+ dl warning, attention, note, deprecated, bug, ...
+ */
+
+dl.bug dt a, dl.deprecated dt a, dl.todo dt a {
+    font-weight: bold !important;
+}
+
+dl.warning, dl.attention, dl.note, dl.deprecated, dl.bug, dl.invariant, dl.pre, dl.post, dl.todo, dl.remark {
+    padding: var(--spacing-medium);
+    margin: var(--spacing-medium) 0;
+    color: var(--page-background-color);
+    overflow: hidden;
+    margin-left: 0;
+    border-radius: var(--border-radius-small);
+}
+
+dl.section dd {
+    margin-bottom: 2px;
+}
+
+dl.warning, dl.attention {
+    background: var(--warning-color);
+    border-left: 8px solid var(--warning-color-dark);
+    color: var(--warning-color-darker);
+}
+
+dl.warning dt, dl.attention dt {
+    color: var(--warning-color-dark);
+}
+
+dl.note, dl.remark {
+    background: var(--note-color);
+    border-left: 8px solid var(--note-color-dark);
+    color: var(--note-color-darker);
+}
+
+dl.note dt, dl.remark dt {
+    color: var(--note-color-dark);
+}
+
+dl.todo {
+    background: var(--todo-color);
+    border-left: 8px solid var(--todo-color-dark);
+    color: var(--todo-color-darker);
+}
+
+dl.todo dt {
+    color: var(--todo-color-dark);
+}
+
+dl.bug dt a {
+    color: var(--todo-color-dark) !important;
+}
+
+dl.bug {
+    background: var(--bug-color);
+    border-left: 8px solid var(--bug-color-dark);
+    color: var(--bug-color-darker);
+}
+
+dl.bug dt a {
+    color: var(--bug-color-dark) !important;
+}
+
+dl.deprecated {
+    background: var(--deprecated-color);
+    border-left: 8px solid var(--deprecated-color-dark);
+    color: var(--deprecated-color-darker);
+}
+
+dl.deprecated dt a {
+    color: var(--deprecated-color-dark) !important;
+}
+
+dl.section dd, dl.bug dd, dl.deprecated dd, dl.todo dd {
+    margin-inline-start: 0px;
+}
+
+dl.invariant, dl.pre, dl.post {
+    background: var(--invariant-color);
+    border-left: 8px solid var(--invariant-color-dark);
+    color: var(--invariant-color-darker);
+}
+
+dl.invariant dt, dl.pre dt, dl.post dt {
+    color: var(--invariant-color-dark);
+}
+
+/*
+ memitem
+ */
+
+div.memdoc, div.memproto, h2.memtitle {
+    box-shadow: none;
+    background-image: none;
+    border: none;
+}
+
+div.memdoc {
+    padding: 0 var(--spacing-medium);
+    background: var(--page-background-color);
+}
+
+h2.memtitle, div.memitem {
+    border: 1px solid var(--separator-color);
+    box-shadow: var(--box-shadow);
+}
+
+h2.memtitle {
+    box-shadow: 0px var(--spacing-medium) 0 -1px var(--fragment-background), var(--box-shadow);
+}
+
+div.memitem {
+    transition: none;
+}
+
+div.memproto, h2.memtitle {
+    background: var(--fragment-background);
+}
+
+h2.memtitle {
+    font-weight: 500;
+    font-size: var(--memtitle-font-size);
+    font-family: var(--font-family-monospace);
+    border-bottom: none;
+    border-top-left-radius: var(--border-radius-medium);
+    border-top-right-radius: var(--border-radius-medium);
+    word-break: break-all;
+    position: relative;
+}
+
+h2.memtitle:after {
+    content: "";
+    display: block;
+    background: var(--fragment-background);
+    height: var(--spacing-medium);
+    bottom: calc(0px - var(--spacing-medium));
+    left: 0;
+    right: -14px;
+    position: absolute;
+    border-top-right-radius: var(--border-radius-medium);
+}
+
+h2.memtitle > span.permalink {
+    font-size: inherit;
+}
+
+h2.memtitle > span.permalink > a {
+    text-decoration: none;
+    padding-left: 3px;
+    margin-right: -4px;
+    user-select: none;
+    display: inline-block;
+    margin-top: -6px;
+}
+
+h2.memtitle > span.permalink > a:hover {
+    color: var(--primary-dark-color) !important;
+}
+
+a:target + h2.memtitle, a:target + h2.memtitle + div.memitem {
+    border-color: var(--primary-light-color);
+}
+
+div.memitem {
+    border-top-right-radius: var(--border-radius-medium);
+    border-bottom-right-radius: var(--border-radius-medium);
+    border-bottom-left-radius: var(--border-radius-medium);
+    overflow: hidden;
+    display: block !important;
+}
+
+div.memdoc {
+    border-radius: 0;
+}
+
+div.memproto {
+    border-radius: 0 var(--border-radius-small) 0 0;
+    overflow: auto;
+    border-bottom: 1px solid var(--separator-color);
+    padding: var(--spacing-medium);
+    margin-bottom: -1px;
+}
+
+div.memtitle {
+    border-top-right-radius: var(--border-radius-medium);
+    border-top-left-radius: var(--border-radius-medium);
+}
+
+div.memproto table.memname {
+    font-family: var(--font-family-monospace);
+    color: var(--page-foreground-color);
+    font-size: var(--memname-font-size);
+    text-shadow: none;
+}
+
+div.memproto div.memtemplate {
+    font-family: var(--font-family-monospace);
+    color: var(--primary-dark-color);
+    font-size: var(--memname-font-size);
+    margin-left: 2px;
+    text-shadow: none;
+}
+
+table.mlabels, table.mlabels > tbody {
+    display: block;
+}
+
+td.mlabels-left {
+    width: auto;
+}
+
+td.mlabels-right {
+    margin-top: 3px;
+    position: sticky;
+    left: 0;
+}
+
+table.mlabels > tbody > tr:first-child {
+    display: flex;
+    justify-content: space-between;
+    flex-wrap: wrap;
+}
+
+.memname, .memitem span.mlabels {
+    margin: 0
+}
+
+/*
+ reflist
+ */
+
+dl.reflist {
+    box-shadow: var(--box-shadow);
+    border-radius: var(--border-radius-medium);
+    border: 1px solid var(--separator-color);
+    overflow: hidden;
+    padding: 0;
+}
+
+
+dl.reflist dt, dl.reflist dd {
+    box-shadow: none;
+    text-shadow: none;
+    background-image: none;
+    border: none;
+    padding: 12px;
+}
+
+
+dl.reflist dt {
+    font-weight: 500;
+    border-radius: 0;
+    background: var(--code-background);
+    border-bottom: 1px solid var(--separator-color);
+    color: var(--page-foreground-color)
+}
+
+
+dl.reflist dd {
+    background: none;
+}
+
+/*
+ Table
+ */
+
+.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname),
+.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody {
+    display: inline-block;
+    max-width: 100%;
+}
+
+.contents > table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname):not(.classindex) {
+    margin-left: calc(0px - var(--spacing-large));
+    margin-right: calc(0px - var(--spacing-large));
+    max-width: calc(100% + 2 * var(--spacing-large));
+}
+
+table.fieldtable,
+table.markdownTable tbody,
+table.doxtable tbody {
+    border: none;
+    margin: var(--spacing-medium) 0;
+    box-shadow: 0 0 0 1px var(--separator-color);
+    border-radius: var(--border-radius-small);
+}
+
+table.markdownTable, table.doxtable, table.fieldtable {
+    padding: 1px;
+}
+
+table.doxtable caption {
+    display: block;
+}
+
+table.fieldtable {
+    border-collapse: collapse;
+    width: 100%;
+}
+
+th.markdownTableHeadLeft,
+th.markdownTableHeadRight,
+th.markdownTableHeadCenter,
+th.markdownTableHeadNone,
+table.doxtable th {
+    background: var(--tablehead-background);
+    color: var(--tablehead-foreground);
+    font-weight: 600;
+    font-size: var(--page-font-size);
+}
+
+th.markdownTableHeadLeft:first-child,
+th.markdownTableHeadRight:first-child,
+th.markdownTableHeadCenter:first-child,
+th.markdownTableHeadNone:first-child,
+table.doxtable tr th:first-child {
+    border-top-left-radius: var(--border-radius-small);
+}
+
+th.markdownTableHeadLeft:last-child,
+th.markdownTableHeadRight:last-child,
+th.markdownTableHeadCenter:last-child,
+th.markdownTableHeadNone:last-child,
+table.doxtable tr th:last-child {
+    border-top-right-radius: var(--border-radius-small);
+}
+
+table.markdownTable td,
+table.markdownTable th,
+table.fieldtable td,
+table.fieldtable th,
+table.doxtable td,
+table.doxtable th {
+    border: 1px solid var(--separator-color);
+    padding: var(--spacing-small) var(--spacing-medium);
+}
+
+table.markdownTable td:last-child,
+table.markdownTable th:last-child,
+table.fieldtable td:last-child,
+table.fieldtable th:last-child,
+table.doxtable td:last-child,
+table.doxtable th:last-child {
+    border-right: none;
+}
+
+table.markdownTable td:first-child,
+table.markdownTable th:first-child,
+table.fieldtable td:first-child,
+table.fieldtable th:first-child,
+table.doxtable td:first-child,
+table.doxtable th:first-child {
+    border-left: none;
+}
+
+table.markdownTable tr:first-child td,
+table.markdownTable tr:first-child th,
+table.fieldtable tr:first-child td,
+table.fieldtable tr:first-child th,
+table.doxtable tr:first-child td,
+table.doxtable tr:first-child th {
+    border-top: none;
+}
+
+table.markdownTable tr:last-child td,
+table.markdownTable tr:last-child th,
+table.fieldtable tr:last-child td,
+table.fieldtable tr:last-child th,
+table.doxtable tr:last-child td,
+table.doxtable tr:last-child th {
+    border-bottom: none;
+}
+
+table.markdownTable tr, table.doxtable tr {
+    border-bottom: 1px solid var(--separator-color);
+}
+
+table.markdownTable tr:last-child, table.doxtable tr:last-child {
+    border-bottom: none;
+}
+
+.full_width_table table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) {
+    display: block;
+}
+
+.full_width_table table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody {
+    display: table;
+    width: 100%;
+}
+
+table.fieldtable th {
+    font-size: var(--page-font-size);
+    font-weight: 600;
+    background-image: none;
+    background-color: var(--tablehead-background);
+    color: var(--tablehead-foreground);
+}
+
+table.fieldtable td.fieldtype, .fieldtable td.fieldname, .fieldtable td.fielddoc, .fieldtable th {
+    border-bottom: 1px solid var(--separator-color);
+    border-right: 1px solid var(--separator-color);
+}
+
+table.fieldtable tr:last-child td:first-child {
+    border-bottom-left-radius: var(--border-radius-small);
+}
+
+table.fieldtable tr:last-child td:last-child {
+    border-bottom-right-radius: var(--border-radius-small);
+}
+
+.memberdecls td.glow, .fieldtable tr.glow {
+    background-color: var(--primary-light-color);
+    box-shadow: none;
+}
+
+table.memberdecls {
+    display: block;
+    -webkit-tap-highlight-color: transparent;
+}
+
+table.memberdecls tr[class^='memitem'] {
+    font-family: var(--font-family-monospace);
+    font-size: var(--code-font-size);
+}
+
+table.memberdecls tr[class^='memitem'] .memTemplParams {
+    font-family: var(--font-family-monospace);
+    font-size: var(--code-font-size);
+    color: var(--primary-dark-color);
+    white-space: normal;
+}
+
+table.memberdecls .memItemLeft,
+table.memberdecls .memItemRight,
+table.memberdecls .memTemplItemLeft,
+table.memberdecls .memTemplItemRight,
+table.memberdecls .memTemplParams {
+    transition: none;
+    padding-top: var(--spacing-small);
+    padding-bottom: var(--spacing-small);
+    border-top: 1px solid var(--separator-color);
+    border-bottom: 1px solid var(--separator-color);
+    background-color: var(--fragment-background);
+}
+
+table.memberdecls .memTemplItemLeft,
+table.memberdecls .memTemplItemRight {
+    padding-top: 2px;
+}
+
+table.memberdecls .memTemplParams {
+    border-bottom: 0;
+    border-left: 1px solid var(--separator-color);
+    border-right: 1px solid var(--separator-color);
+    border-radius: var(--border-radius-small) var(--border-radius-small) 0 0;
+    padding-bottom: var(--spacing-small);
+}
+
+table.memberdecls .memTemplItemLeft {
+    border-radius: 0 0 0 var(--border-radius-small);
+    border-left: 1px solid var(--separator-color);
+    border-top: 0;
+}
+
+table.memberdecls .memTemplItemRight {
+    border-radius: 0 0 var(--border-radius-small) 0;
+    border-right: 1px solid var(--separator-color);
+    padding-left: 0;
+    border-top: 0;
+}
+
+table.memberdecls .memItemLeft {
+    border-radius: var(--border-radius-small) 0 0 var(--border-radius-small);
+    border-left: 1px solid var(--separator-color);
+    padding-left: var(--spacing-medium);
+    padding-right: 0;
+}
+
+table.memberdecls .memItemRight  {
+    border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0;
+    border-right: 1px solid var(--separator-color);
+    padding-right: var(--spacing-medium);
+    padding-left: 0;
+
+}
+
+table.memberdecls .mdescLeft, table.memberdecls .mdescRight {
+    background: none;
+    color: var(--page-foreground-color);
+    padding: var(--spacing-small) 0;
+}
+
+table.memberdecls .memItemLeft,
+table.memberdecls .memTemplItemLeft {
+    padding-right: var(--spacing-medium);
+}
+
+table.memberdecls .memSeparator {
+    background: var(--page-background-color);
+    height: var(--spacing-large);
+    border: 0;
+    transition: none;
+}
+
+table.memberdecls .groupheader {
+    margin-bottom: var(--spacing-large);
+}
+
+table.memberdecls .inherit_header td {
+    padding: 0 0 var(--spacing-medium) 0;
+    text-indent: -12px;
+    color: var(--page-secondary-foreground-color);
+}
+
+table.memberdecls img[src="closed.png"],
+table.memberdecls img[src="open.png"],
+div.dynheader img[src="open.png"],
+div.dynheader img[src="closed.png"] {
+    width: 0; 
+    height: 0; 
+    border-left: 4px solid transparent;
+    border-right: 4px solid transparent;
+    border-top: 5px solid var(--primary-color);
+    margin-top: 8px;
+    display: block;
+    float: left;
+    margin-left: -10px;
+    transition: transform 0.25s ease-out;
+}
+
+table.memberdecls img {
+    margin-right: 10px;
+}
+
+table.memberdecls img[src="closed.png"],
+div.dynheader img[src="closed.png"] {
+    transform: rotate(-90deg);
+    
+}
+
+.compoundTemplParams {
+    font-family: var(--font-family-monospace);
+    color: var(--primary-dark-color);
+    font-size: var(--code-font-size);
+}
+
+@media screen and (max-width: 767px) {
+
+    table.memberdecls .memItemLeft,
+    table.memberdecls .memItemRight,
+    table.memberdecls .mdescLeft,
+    table.memberdecls .mdescRight,
+    table.memberdecls .memTemplItemLeft,
+    table.memberdecls .memTemplItemRight,
+    table.memberdecls .memTemplParams {
+        display: block;
+        text-align: left;
+        padding-left: var(--spacing-large);
+        margin: 0 calc(0px - var(--spacing-large)) 0 calc(0px - var(--spacing-large));
+        border-right: none;
+        border-left: none;
+        border-radius: 0;
+        white-space: normal;
+    }
+
+    table.memberdecls .memItemLeft,
+    table.memberdecls .mdescLeft,
+    table.memberdecls .memTemplItemLeft {
+        border-bottom: 0;
+        padding-bottom: 0;
+    }
+
+    table.memberdecls .memTemplItemLeft {
+        padding-top: 0;
+    }
+
+    table.memberdecls .mdescLeft {
+        margin-bottom: calc(0px - var(--page-font-size));
+    }
+
+    table.memberdecls .memItemRight, 
+    table.memberdecls .mdescRight,
+    table.memberdecls .memTemplItemRight {
+        border-top: 0;
+        padding-top: 0;
+        padding-right: var(--spacing-large);
+        overflow-x: auto;
+    }
+
+    table.memberdecls tr[class^='memitem']:not(.inherit) {
+        display: block;
+        width: calc(100vw - 2 * var(--spacing-large));
+    }
+
+    table.memberdecls .mdescRight {
+        color: var(--page-foreground-color);
+    }
+
+    table.memberdecls tr.inherit {
+        visibility: hidden;
+    }
+
+    table.memberdecls tr[style="display: table-row;"] {
+        display: block !important;
+        visibility: visible;
+        width: calc(100vw - 2 * var(--spacing-large));
+        animation: fade .5s;
+    }
+
+    @keyframes fade {
+        0% {
+            opacity: 0;
+            max-height: 0;
+        }
+
+        100% {
+            opacity: 1;
+            max-height: 200px;
+        }
+    }
+}
+
+
+/*
+ Horizontal Rule
+ */
+
+hr {
+    margin-top: var(--spacing-large);
+    margin-bottom: var(--spacing-large);
+    height: 1px;
+    background-color: var(--separator-color);
+    border: 0;
+}
+
+.contents hr {
+    box-shadow: 100px 0 0 var(--separator-color),
+                -100px 0 0 var(--separator-color),
+                500px 0 0 var(--separator-color),
+                -500px 0 0 var(--separator-color),
+                1500px 0 0 var(--separator-color),
+                -1500px 0 0 var(--separator-color),
+                2000px 0 0 var(--separator-color),
+                -2000px 0 0 var(--separator-color);
+}
+
+.contents img, .contents .center, .contents center, .contents div.image object {
+    max-width: 100%;
+    overflow: auto;
+}
+
+@media screen and (max-width: 767px) {
+    .contents .dyncontent > .center, .contents > center {
+        margin-left: calc(0px - var(--spacing-large));
+        margin-right: calc(0px - var(--spacing-large));
+        max-width: calc(100% + 2 * var(--spacing-large));
+    }
+}
+
+/*
+ Directories
+ */
+div.directory {
+    border-top: 1px solid var(--separator-color);
+    border-bottom: 1px solid var(--separator-color);
+    width: auto;
+}
+
+table.directory {
+    font-family: var(--font-family);
+    font-size: var(--page-font-size);
+    font-weight: normal;
+    width: 100%;
+}
+
+table.directory td.entry, table.directory td.desc {
+    padding: calc(var(--spacing-small) / 2) var(--spacing-small);
+    line-height: var(--table-line-height);
+}
+
+table.directory tr.even td:last-child {
+    border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0;
+}
+
+table.directory tr.even td:first-child {
+    border-radius: var(--border-radius-small) 0 0 var(--border-radius-small);
+}
+
+table.directory tr.even:last-child td:last-child {
+    border-radius: 0 var(--border-radius-small) 0 0;
+}
+
+table.directory tr.even:last-child td:first-child {
+    border-radius: var(--border-radius-small) 0 0 0;
+}
+
+table.directory td.desc {
+    min-width: 250px;
+}
+
+table.directory tr.even {
+    background-color: var(--odd-color);
+}
+
+table.directory tr.odd {
+    background-color: transparent;
+}
+
+.icona {
+    width: auto;
+    height: auto;
+    margin: 0 var(--spacing-small);
+}
+
+.icon {
+    background: var(--primary-color);
+    border-radius: var(--border-radius-small);
+    font-size: var(--page-font-size);
+    padding: calc(var(--page-font-size) / 5);
+    line-height: var(--page-font-size);
+    transform: scale(0.8);
+    height: auto;
+    width: var(--page-font-size);
+    user-select: none;
+}
+
+.iconfopen, .icondoc, .iconfclosed {
+    background-position: center;
+    margin-bottom: 0;
+    height: var(--table-line-height);
+}
+
+.icondoc {
+    filter: saturate(0.2);
+}
+
+@media screen and (max-width: 767px) {
+    div.directory {
+        margin-left: calc(0px - var(--spacing-large));
+        margin-right: calc(0px - var(--spacing-large));
+    }
+}
+
+@media (prefers-color-scheme: dark) {
+    html:not(.light-mode) .iconfopen, html:not(.light-mode) .iconfclosed {
+        filter: hue-rotate(180deg) invert();
+    }
+}
+
+html.dark-mode .iconfopen, html.dark-mode .iconfclosed {
+    filter: hue-rotate(180deg) invert();
+}
+
+/*
+ Class list
+ */
+
+.classindex dl.odd {
+    background: var(--odd-color);
+    border-radius: var(--border-radius-small);
+}
+
+.classindex dl.even {
+    background-color: transparent;
+}
+
+/* 
+ Class Index Doxygen 1.8 
+*/
+
+table.classindex {
+    margin-left: 0;
+    margin-right: 0;
+    width: 100%;
+}
+
+table.classindex table div.ah {
+    background-image: none;
+    background-color: initial;
+    border-color: var(--separator-color);
+    color: var(--page-foreground-color);
+    box-shadow: var(--box-shadow);
+    border-radius: var(--border-radius-large);
+    padding: var(--spacing-small);
+}
+
+div.qindex {
+    background-color: var(--odd-color);
+    border-radius: var(--border-radius-small);
+    border: 1px solid var(--separator-color);
+    padding: var(--spacing-small) 0;
+}
+
+/*
+  Footer and nav-path
+ */
+
+#nav-path {
+    width: 100%;
+}
+
+#nav-path ul {
+    background-image: none;
+    background: var(--page-background-color);
+    border: none;
+    border-top: 1px solid var(--separator-color);
+    border-bottom: 1px solid var(--separator-color);
+    border-bottom: 0;
+    box-shadow: 0 0.75px 0 var(--separator-color);
+    font-size: var(--navigation-font-size);
+}
+
+img.footer {
+    width: 60px;
+}
+
+.navpath li.footer {
+    color: var(--page-secondary-foreground-color);
+}
+
+address.footer {
+    color: var(--page-secondary-foreground-color);
+    margin-bottom: var(--spacing-large);
+}
+
+#nav-path li.navelem {
+    background-image: none;
+    display: flex;
+    align-items: center;
+}
+
+.navpath li.navelem a {
+    text-shadow: none;
+    display: inline-block;
+    color: var(--primary-color) !important;
+}
+
+.navpath li.navelem b {
+    color: var(--primary-dark-color);
+    font-weight: 500;
+}
+
+li.navelem {
+    padding: 0;
+    margin-left: -8px;
+}
+
+li.navelem:first-child {
+    margin-left: var(--spacing-large);
+}
+
+li.navelem:first-child:before {
+    display: none;
+}
+
+#nav-path li.navelem:after {
+    content: '';
+    border: 5px solid var(--page-background-color);
+    border-bottom-color: transparent;
+    border-right-color: transparent;
+    border-top-color: transparent;
+    transform: translateY(-1px) scaleY(4.2);
+    z-index: 10;
+    margin-left: 6px;
+}
+
+#nav-path li.navelem:before {
+    content: '';
+    border: 5px solid var(--separator-color);
+    border-bottom-color: transparent;
+    border-right-color: transparent;
+    border-top-color: transparent;
+    transform: translateY(-1px) scaleY(3.2);
+    margin-right: var(--spacing-small);
+}
+
+.navpath li.navelem a:hover {
+    color: var(--primary-color);
+}
+
+/*
+ Scrollbars for Webkit
+*/
+
+#nav-tree::-webkit-scrollbar,
+div.fragment::-webkit-scrollbar,
+pre.fragment::-webkit-scrollbar,
+div.memproto::-webkit-scrollbar,
+.contents center::-webkit-scrollbar,
+.contents .center::-webkit-scrollbar,
+.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar,
+div.contents .toc::-webkit-scrollbar,
+.contents .dotgraph::-webkit-scrollbar,
+.contents .tabs-overview-container::-webkit-scrollbar {
+    background: transparent;
+    width: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding));
+    height: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding));
+}
+
+#nav-tree::-webkit-scrollbar-thumb,
+div.fragment::-webkit-scrollbar-thumb,
+pre.fragment::-webkit-scrollbar-thumb,
+div.memproto::-webkit-scrollbar-thumb,
+.contents center::-webkit-scrollbar-thumb,
+.contents .center::-webkit-scrollbar-thumb,
+.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-thumb,
+div.contents .toc::-webkit-scrollbar-thumb,
+.contents .dotgraph::-webkit-scrollbar-thumb,
+.contents .tabs-overview-container::-webkit-scrollbar-thumb {
+    background-color: transparent;
+    border: var(--webkit-scrollbar-padding) solid transparent;
+    border-radius: calc(var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding));
+    background-clip: padding-box;  
+}
+
+#nav-tree:hover::-webkit-scrollbar-thumb,
+div.fragment:hover::-webkit-scrollbar-thumb,
+pre.fragment:hover::-webkit-scrollbar-thumb,
+div.memproto:hover::-webkit-scrollbar-thumb,
+.contents center:hover::-webkit-scrollbar-thumb,
+.contents .center:hover::-webkit-scrollbar-thumb,
+.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody:hover::-webkit-scrollbar-thumb,
+div.contents .toc:hover::-webkit-scrollbar-thumb,
+.contents .dotgraph:hover::-webkit-scrollbar-thumb,
+.contents .tabs-overview-container:hover::-webkit-scrollbar-thumb {
+    background-color: var(--webkit-scrollbar-color);
+}
+
+#nav-tree::-webkit-scrollbar-track,
+div.fragment::-webkit-scrollbar-track,
+pre.fragment::-webkit-scrollbar-track,
+div.memproto::-webkit-scrollbar-track,
+.contents center::-webkit-scrollbar-track,
+.contents .center::-webkit-scrollbar-track,
+.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-track,
+div.contents .toc::-webkit-scrollbar-track,
+.contents .dotgraph::-webkit-scrollbar-track,
+.contents .tabs-overview-container::-webkit-scrollbar-track {
+    background: transparent;
+}
+
+#nav-tree::-webkit-scrollbar-corner {
+    background-color: var(--side-nav-background);
+}
+
+#nav-tree,
+div.fragment,
+pre.fragment,
+div.memproto,
+.contents center,
+.contents .center,
+.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody,
+div.contents .toc {
+    overflow-x: auto;
+    overflow-x: overlay;
+}
+
+#nav-tree {
+    overflow-x: auto;
+    overflow-y: auto;
+    overflow-y: overlay;
+}
+
+/*
+ Scrollbars for Firefox
+*/
+
+#nav-tree,
+div.fragment,
+pre.fragment,
+div.memproto,
+.contents center,
+.contents .center,
+.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody,
+div.contents .toc,
+.contents .dotgraph,
+.contents .tabs-overview-container {
+    scrollbar-width: thin;
+}
+
+/*
+  Optional Dark mode toggle button
+*/
+
+doxygen-awesome-dark-mode-toggle {
+    display: inline-block;
+    margin: 0 0 0 var(--spacing-small);
+    padding: 0;
+    width: var(--searchbar-height);
+    height: var(--searchbar-height);
+    background: none;
+    border: none;
+    border-radius: var(--searchbar-height);
+    vertical-align: middle;
+    text-align: center;
+    line-height: var(--searchbar-height);
+    font-size: 22px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    user-select: none;
+    cursor: pointer;
+}
+
+doxygen-awesome-dark-mode-toggle > svg {
+    transition: transform .1s ease-in-out;
+}
+
+doxygen-awesome-dark-mode-toggle:active > svg {
+    transform: scale(.5);
+}
+
+doxygen-awesome-dark-mode-toggle:hover {
+    background-color: rgba(0,0,0,.03);
+}
+
+html.dark-mode doxygen-awesome-dark-mode-toggle:hover {
+    background-color: rgba(0,0,0,.18);
+}
+
+/*
+ Optional fragment copy button
+*/
+.doxygen-awesome-fragment-wrapper {
+    position: relative;
+}
+
+doxygen-awesome-fragment-copy-button {
+    opacity: 0;
+    background: var(--fragment-background);
+    width: 28px;
+    height: 28px;
+    position: absolute;
+    right: calc(var(--spacing-large) - (var(--spacing-large) / 2.5));
+    top: calc(var(--spacing-large) - (var(--spacing-large) / 2.5));
+    border: 1px solid var(--fragment-foreground);
+    cursor: pointer;
+    border-radius: var(--border-radius-small);
+    display: flex;
+    justify-content: center;
+    align-items: center;
+}
+
+.doxygen-awesome-fragment-wrapper:hover doxygen-awesome-fragment-copy-button, doxygen-awesome-fragment-copy-button.success {
+    opacity: .28;
+}
+
+doxygen-awesome-fragment-copy-button:hover, doxygen-awesome-fragment-copy-button.success {
+    opacity: 1 !important;
+}
+
+doxygen-awesome-fragment-copy-button:active:not([class~=success]) svg {
+    transform: scale(.91);
+}
+
+doxygen-awesome-fragment-copy-button svg {
+    fill: var(--fragment-foreground);
+    width: 18px;
+    height: 18px;
+}
+
+doxygen-awesome-fragment-copy-button.success svg {
+    fill: rgb(14, 168, 14);
+}
+
+doxygen-awesome-fragment-copy-button.success {
+    border-color: rgb(14, 168, 14);
+}
+
+@media screen and (max-width: 767px) {
+    .textblock > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button,
+    .textblock li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button,
+    .memdoc li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button,
+    .memdoc > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button,
+    dl dd > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button {
+        right: 0;
+    }
+}
+
+/*
+ Optional paragraph link button
+*/
+
+a.anchorlink {
+    font-size: 90%;
+    margin-left: var(--spacing-small);
+    color: var(--page-foreground-color) !important;
+    text-decoration: none;
+    opacity: .15;
+    display: none;
+    transition: opacity .1s ease-in-out, color .1s ease-in-out;
+}
+
+a.anchorlink svg {
+    fill: var(--page-foreground-color);
+}
+
+h3 a.anchorlink svg, h4 a.anchorlink svg {
+    margin-bottom: -3px;
+    margin-top: -4px;
+}
+
+a.anchorlink:hover {
+    opacity: .45;
+}
+
+h2:hover a.anchorlink, h1:hover a.anchorlink, h3:hover a.anchorlink, h4:hover a.anchorlink  {
+    display: inline-block;
+}
+
+/*
+ Optional tab feature
+*/
+
+.tabbed {
+    margin: var(--spacing-medium) auto;
+}
+
+.tabbed ul {
+    padding-inline-start: 0px;
+    margin: 0;
+    padding: var(--spacing-small) 0;
+    border-bottom: 1px solid var(--separator-color);
+}
+
+.tabbed li {
+    display: none;
+}
+
+.tabbed li.selected {
+    display: block;
+}
+
+.tabs-overview-container {
+    overflow-x: auto;
+    display: block;
+    overflow-y: visible;
+}
+
+.tabs-overview {
+    border-bottom: 1px solid var(--separator-color);
+    display: flex;
+    flex-direction: row;
+}
+
+.tabs-overview button.tab-button {
+    color: var(--page-foreground-color);
+    margin: 0;
+    border: none;
+    background: transparent;
+    padding: var(--spacing-small) 0;
+    display: inline-block;
+    font-size: var(--page-font-size);
+    cursor: pointer;
+    box-shadow: 0 1px 0 0 var(--separator-color);
+    position: relative;
+}
+
+.tabs-overview button.tab-button .tab-title {
+    float: left;
+    white-space: nowrap;
+    padding: var(--spacing-small) var(--spacing-large);
+    border-radius: var(--border-radius-medium);
+}
+
+.tabs-overview button.tab-button:not(:last-child) .tab-title {
+    box-shadow: 8px 0 0 -7px var(--separator-color);
+}
+
+.tabs-overview button.tab-button:hover .tab-title {
+    background: var(--separator-color);
+    box-shadow: none;
+}
+
+.tabs-overview button.tab-button.active {
+    color: var(--primary-color);
+}
+
+.tabs-overview button.tab-button.active::after {
+    content: '';
+    display: block;
+    position: absolute;
+    left: 0px;
+    bottom: 0;
+    right: 0px;
+    height: 3px;
+    border-radius: var(--border-radius-small) var(--border-radius-small) 0 0;
+    background-color: var(--primary-color);
+}

+ 2728 - 0
docs/doxygen.conf

@@ -0,0 +1,2728 @@
+# Doxyfile 1.9.7
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+#
+# Note:
+#
+# Use doxygen to compare the used configuration file with the template
+# configuration file:
+# doxygen -x [configFile]
+# Use doxygen to compare the used configuration file with the template
+# configuration file without replacing the environment variables or CMake type
+# replacement variables:
+# doxygen -x_noenv [configFile]
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the configuration
+# file that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "libigl"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         = "v2.5.0"
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          = 
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       =
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096
+# sub-directories (in 2 levels) under the output directory of each output format
+# and will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to
+# control the number of sub-directories.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# Controls the number of sub-directories that will be created when
+# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every
+# level increment doubles the number of directories, resulting in 4096
+# directories at level 8 which is the default and also the maximum value. The
+# sub-directories are organized in 2 levels, the first level always has a fixed
+# number of 16 directories.
+# Minimum value: 0, maximum value: 8, default value: 8.
+# This tag requires that the tag CREATE_SUBDIRS is set to YES.
+
+CREATE_SUBDIRS_LEVEL   = 8
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,
+# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English
+# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,
+# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with
+# English messages), Korean, Korean-en (Korean with English messages), Latvian,
+# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,
+# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,
+# Swedish, Turkish, Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
+# such as
+# /***************
+# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
+# Javadoc-style will behave just like regular comments and it will not be
+# interpreted by doxygen.
+# The default value is: NO.
+
+JAVADOC_BANNER         = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# By default Python docstrings are displayed as preformatted text and doxygen's
+# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
+# doxygen's special commands can be used and the contents of the docstring
+# documentation blocks is shown as doxygen documentation.
+# The default value is: YES.
+
+PYTHON_DOCSTRING       = YES
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:^^"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". Note that you cannot put \n's in the value part of an alias
+# to insert newlines (in the resulting output). You can put ^^ in the value part
+# of an alias to insert a newline as if a physical newline was in the original
+# file. When you need a literal { or } or , in the value part of an alias you
+# have to escape them by means of a backslash (\), this can lead to conflicts
+# with the commands \{ and \} for these it is advised to use the version @{ and
+# @} or use a double escape (\\{ and \\})
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
+# sources only. Doxygen will then generate output that is more tailored for that
+# language. For instance, namespaces will be presented as modules, types will be
+# separated into more groups, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_SLICE  = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
+# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice,
+# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
+# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
+# tries to guess whether the code is fixed or free formatted code, this is the
+# default for Fortran type files). For instance to make doxygen treat .inc files
+# as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen. When specifying no_extension you should add
+# * to the FILE_PATTERNS.
+#
+# Note see also the list of default file extension mappings.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See https://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 5.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS   = 5
+
+# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to
+# generate identifiers for the Markdown headings. Note: Every identifier is
+# unique.
+# Possible values are: DOXYGEN Use a fixed 'autotoc_md' string followed by a
+# sequence number starting at 0. and GITHUB Use the lower case version of title
+# with any whitespace replaced by '-' and punctations characters removed..
+# The default value is: DOXYGEN.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+MARKDOWN_ID_STYLE      = DOXYGEN
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use
+# during processing. When set to 0 doxygen will based this on the number of
+# cores available in the system. You can set it explicitly to a value larger
+# than 0 to get more control over the balance between CPU load and processing
+# speed. At this moment only the input processing can be done using multiple
+# threads. Since this is still an experimental feature the default is set to 1,
+# which effectively disables parallel processing. Please report any issues you
+# encounter. Generating dot graphs in parallel is controlled by the
+# DOT_NUM_THREADS setting.
+# Minimum value: 0, maximum value: 32, default value: 1.
+
+NUM_PROC_THREADS       = 1
+
+# If the TIMESTAMP tag is set different from NO then each generated page will
+# contain the date or date and time when the page was generated. Setting this to
+# NO can help when comparing the output of multiple runs.
+# Possible values are: YES, NO, DATETIME and DATE.
+# The default value is: NO.
+
+TIMESTAMP              = NO
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
+# methods of a class will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIV_VIRTUAL   = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If this flag is set to YES, the name of an unnamed parameter in a declaration
+# will be determined by the corresponding definition. By default unnamed
+# parameters remain unnamed in the output.
+# The default value is: YES.
+
+RESOLVE_UNNAMED_PARAMS = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# will also hide undocumented C++ concepts if enabled. This option has no effect
+# if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# declarations. If set to NO, these declarations will be included in the
+# documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
+# able to match the capabilities of the underlying filesystem. In case the
+# filesystem is case sensitive (i.e. it supports files in the same directory
+# whose names only differ in casing), the option must be set to YES to properly
+# deal with such files in case they appear in the input. For filesystems that
+# are not case sensitive the option should be set to NO to properly deal with
+# output files written for symbols that only differ in casing, such as for two
+# classes, one named CLASS and the other named Class, and to also support
+# references to files without having to specify the exact matching casing. On
+# Windows (including Cygwin) and MacOS, users should typically set this option
+# to NO, whereas on Linux or other Unix flavors it should typically be set to
+# YES.
+# Possible values are: SYSTEM, NO and YES.
+# The default value is: SYSTEM.
+
+CASE_SENSE_NAMES       = SYSTEM
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class
+# will show which file needs to be included to use the class.
+# The default value is: YES.
+
+SHOW_HEADERFILE        = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = NO
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = NO
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= NO
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file. See also section "Changing the
+# layout of pages" for information.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as documenting some parameters in
+# a documented function twice, or documenting parameters that don't exist or
+# using markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete
+# function parameter documentation. If set to NO, doxygen will accept that some
+# parameters have no documentation without warning.
+# The default value is: YES.
+
+WARN_IF_INCOMPLETE_DOC = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong parameter
+# documentation, but not about the absence of documentation. If EXTRACT_ALL is
+# set to YES then this flag will automatically be disabled. See also
+# WARN_IF_INCOMPLETE_DOC
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about
+# undocumented enumeration values. If set to NO, doxygen will accept
+# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: NO.
+
+WARN_IF_UNDOC_ENUM_VAL = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
+# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
+# at the end of the doxygen process doxygen will return with a non-zero status.
+# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves
+# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not
+# write the warning messages in between other messages but write them at the end
+# of a run, in case a WARN_LOGFILE is defined the warning messages will be
+# besides being in the defined file also be shown at the end of a run, unless
+# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case
+# the behavior will remain as with the setting FAIL_ON_WARNINGS.
+# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT.
+# The default value is: NO.
+
+WARN_AS_ERROR          = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# See also: WARN_LINE_FORMAT
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# In the $text part of the WARN_FORMAT command it is possible that a reference
+# to a more specific place is given. To make it easier to jump to this place
+# (outside of doxygen) the user can define a custom "cut" / "paste" string.
+# Example:
+# WARN_LINE_FORMAT = "'vi $file +$line'"
+# See also: WARN_FORMAT
+# The default value is: at line $line of file $file.
+
+WARN_LINE_FORMAT       = "at line $line of file $file"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr). In case the file specified cannot be opened for writing the
+# warning and error messages are written to standard error. When as file - is
+# specified the warning and error messages are written to standard output
+# (stdout).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = docs/index.md include/igl/ 
+# read !grep -l "///" include/igl/**/*.h | tr '\n' ' '
+
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see:
+# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
+# See also: INPUT_FILE_ENCODING
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify
+# character encoding on a per file pattern basis. Doxygen will compare the file
+# name with each pattern and apply the encoding instead of the default
+# INPUT_ENCODING) if there is a match. The character encodings are a list of the
+# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding
+# "INPUT_ENCODING" for further information on supported encodings.
+
+INPUT_FILE_ENCODING    =
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# Note the list of default checked file patterns might differ from the list of
+# default file extension mappings.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml,
+# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C
+# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
+# *.vhdl, *.ucf, *.qsf and *.ice.
+
+FILE_PATTERNS          = *.h
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                = include/igl/FastWindingNumberForSoups.h
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# ANamespace::AClass, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that doxygen will use the data processed and written to standard output
+# for further processing, therefore nothing else, like debug statements or used
+# commands (so in case of a Windows batch file always use @echo OFF), should be
+# written to standard output.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE = docs/index.md
+
+# The Fortran standard specifies that for fixed formatted Fortran code all
+# characters from position 72 are to be considered as comment. A common
+# extension is to allow longer lines before the automatic comment starts. The
+# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can
+# be processed before the automatic comment starts.
+# Minimum value: 7, maximum value: 10000, default value: 72.
+
+FORTRAN_COMMENT_AFTER  = 72
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# entity all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see https://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)
+# that should be ignored while generating the index headers. The IGNORE_PREFIX
+# tag works for classes, function and member names. The entity will be placed in
+# the alphabetical list under the first letter of the entity name that remains
+# after removing the prefix.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = dox
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# Note: Since the styling of scrollbars can currently not be overruled in
+# Webkit/Chromium, the styling will be left out of the default doxygen.css if
+# one or more extra stylesheets have been specified. So if scrollbar
+# customization is desired it has to be added explicitly. For an example see the
+# documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  = docs/doxygen-awesome.css
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output
+# should be rendered with a dark or light theme.
+# Possible values are: LIGHT always generate light mode output, DARK always
+# generate dark mode output, AUTO_LIGHT automatically set the mode according to
+# the user preference, use light mode if no preference is set (the default),
+# AUTO_DARK automatically set the mode according to the user preference, use
+# dark mode if no preference is set and TOGGLE allow to user to switch between
+# light and dark mode via a button.
+# The default value is: AUTO_LIGHT.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE        = LIGHT
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a color-wheel, see
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 240
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use gray-scales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 102
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
+# documentation will contain a main index with vertical navigation menus that
+# are dynamically created via JavaScript. If disabled, the navigation index will
+# consists of multiple levels of tabs that are statically embedded in every HTML
+# page. Disable this option to support browsers that do not have JavaScript,
+# like the Qt help browser.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_MENUS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see:
+# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
+# create a documentation set, doxygen will generate a Makefile in the HTML
+# output directory. Running make will produce the docset in that directory and
+# running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
+# genXcode/_index.html for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag determines the URL of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDURL         =
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# on Windows. In the beginning of 2021 Microsoft took the original page, with
+# a.o. the download links, offline the HTML help workshop was already many years
+# in maintenance mode). You can download the HTML help workshop from the web
+# archives at Installation executable (see:
+# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo
+# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe).
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the main .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# The SITEMAP_URL tag is used to specify the full URL of the place where the
+# generated documentation will be placed on the server by the user during the
+# deployment of the documentation. The generated sitemap is called sitemap.xml
+# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL
+# is specified no sitemap is generated. For information about the sitemap
+# protocol see https://www.sitemaps.org
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SITEMAP_URL            =
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location (absolute path
+# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
+# run qhelpgenerator on the generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine tune the look of the index (see "Fine-tuning the output"). As an
+# example, the default style sheet generated by doxygen has an example that
+# shows how to put an image at the root of the tree instead of the PROJECT_NAME.
+# Since the tree basically has the same information as the tab index, you could
+# consider setting DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = YES
+
+# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the
+# FULL_SIDEBAR option determines if the side bar is limited to only the treeview
+# area (value NO) or if it should extend to the full height of the window (value
+# YES). Setting this to YES gives a layout similar to
+# https://docs.readthedocs.io with more room for contents, but less room for the
+# project logo, title, and description. If either GENERATE_TREEVIEW or
+# DISABLE_INDEX is set to NO, this option has no effect.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FULL_SIDEBAR           = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email
+# addresses.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+OBFUSCATE_EMAILS       = YES
+
+# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
+# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
+# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
+# the HTML output. These images will generally look nicer at scaled resolutions.
+# Possible values are: png (the default) and svg (looks nicer but requires the
+# pdf2svg or inkscape tool).
+# The default value is: png.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FORMULA_FORMAT    = png
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
+# to create new LaTeX commands to be used in formulas as building blocks. See
+# the section "Including formulas" for details.
+
+FORMULA_MACROFILE      =
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# https://www.mathjax.org) which uses client side JavaScript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = YES
+
+# With MATHJAX_VERSION it is possible to specify the MathJax version to be used.
+# Note that the different versions of MathJax have different requirements with
+# regards to the different settings, so it is possible that also other MathJax
+# settings have to be changed when switching between the different MathJax
+# versions.
+# Possible values are: MathJax_2 and MathJax_3.
+# The default value is: MathJax_2.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_VERSION        = MathJax_2
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. For more details about the output format see MathJax
+# version 2 (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3
+# (see:
+# http://docs.mathjax.org/en/latest/web/components/output.html).
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility. This is the name for Mathjax version 2, for MathJax version 3
+# this will be translated into chtml), NativeMML (i.e. MathML. Only supported
+# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This
+# is the name for Mathjax version 3, for MathJax version 2 this will be
+# translated into HTML-CSS) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from https://www.mathjax.org before deployment. The default value is:
+# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2
+# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        =
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# for MathJax version 2 (see
+# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions):
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# For example for MathJax version 3 (see
+# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):
+# MATHJAX_EXTENSIONS = ams
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using JavaScript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/). See the section "External Indexing and Searching" for
+# details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when not enabling USE_PDFLATEX the default is latex when enabling
+# USE_PDFLATEX the default is pdflatex and when in the later case latex is
+# chosen this is overwritten by pdflatex. For specific output languages the
+# default can have been set differently, this depends on the implementation of
+# the output language.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         =
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# Note: This tag is used in the Makefile / make.bat.
+# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
+# (.tex).
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
+# generate index for LaTeX. In case there is no backslash (\) as first character
+# it will be automatically added in the LaTeX code.
+# Note: This tag is used in the generated output file (.tex).
+# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
+# The default value is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_MAKEINDEX_CMD    = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for
+# the generated LaTeX document. The header should contain everything until the
+# first chapter. If it is left blank doxygen will generate a standard header. It
+# is highly recommended to start with a default header using
+# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty
+# and then modify the file new_header.tex. See also section "Doxygen usage" for
+# information on how to generate the default header that doxygen normally uses.
+#
+# Note: Only use a user-defined header if you know what you are doing!
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. The following
+# commands have a special meaning inside the header (and footer): For a
+# description of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for
+# the generated LaTeX document. The footer should contain everything after the
+# last chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer. See also section "Doxygen
+# usage" for information on how to generate the default footer that doxygen
+# normally uses. Note: Only use a user-defined footer if you know what you are
+# doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
+# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
+# files. Set this option to YES, to get a higher quality PDF documentation.
+#
+# See also section LATEX_CMD_NAME for selecting the engine.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# The LATEX_BATCHMODE tag ignals the behavior of LaTeX in case of an error.
+# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch
+# mode nothing is printed on the terminal, errors are scrolled as if <return> is
+# hit at every error; missing files that TeX tries to input or request from
+# keyboard input (\read on a not open input stream) cause the job to abort,
+# NON_STOP In nonstop mode the diagnostic message will appear on the terminal,
+# but there is no possibility of user interaction just like in batch mode,
+# SCROLL In scroll mode, TeX will stop only for missing files to input or if
+# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at
+# each error, asking for user intervention.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
+# path from which the emoji images will be read. If a relative path is entered,
+# it will be relative to the LATEX_OUTPUT directory. If left blank the
+# LATEX_OUTPUT directory will be used.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EMOJI_DIRECTORY  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# configuration file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's configuration file. A template extensions file can be
+# generated using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
+# namespace members in file scope as well, matching the HTML output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_NS_MEMB_FILE_SCOPE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures
+# the structure of the code including all documentation. Note that this feature
+# is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of
+# RECURSIVE has no effect here.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             = IGL_INLINE=""
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to diagram generator tools
+#---------------------------------------------------------------------------
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of
+# subgraphs. When you want a differently looking font in the dot files that
+# doxygen generates you can specify fontname, fontcolor and fontsize attributes.
+# For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node,
+# Edge and Graph Attributes specification</a> You need to make sure dot is able
+# to find the font, which can be done by putting it in a standard location or by
+# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font. Default graphviz fontsize is 14.
+# The default value is: fontname=Helvetica,fontsize=10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_COMMON_ATTR        = "fontname=Helvetica,fontsize=10"
+
+# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can
+# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a
+# href=https://graphviz.org/doc/info/arrows.html>Complete documentation about
+# arrows shapes.</a>
+# The default value is: labelfontname=Helvetica,labelfontsize=10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_EDGE_ATTR          = "labelfontname=Helvetica,labelfontsize=10"
+
+# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes
+# around nodes set 'shape=plain' or 'shape=plaintext' <a
+# href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a>
+# The default value is: shape=box,height=0.2,width=0.4.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NODE_ATTR          = "shape=box,height=0.2,width=0.4"
+
+# You can set the path where dot can find font specified with fontname in
+# DOT_COMMON_ATTR and others dot attributes.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will
+# generate a graph for each documented class showing the direct and indirect
+# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and
+# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case
+# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the
+# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used.
+# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance
+# relations will be shown as texts / links.
+# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN.
+# The default value is: YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies. See also the chapter Grouping
+# in the manual.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
+# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
+# tag is set to YES, doxygen will add type and arguments for attributes and
+# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
+# will not generate fields with class member information in the UML graphs. The
+# class diagrams will look similar to the default class diagrams but using UML
+# notation for the relationships.
+# Possible values are: NO, YES and NONE.
+# The default value is: NO.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+DOT_UML_DETAILS        = NO
+
+# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
+# to display on a single line. If the actual line length exceeds this threshold
+# significantly it will wrapped across multiple lines. Some heuristics are apply
+# to avoid ugly line breaks.
+# Minimum value: 0, maximum value: 1000, default value: 17.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_WRAP_THRESHOLD     = 17
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels
+# of child directories generated in directory dependency graphs by dot.
+# Minimum value: 1, maximum value: 25, default value: 1.
+# This tag requires that the tag DIRECTORY_GRAPH is set to YES.
+
+DIR_GRAPH_MAX_DEPTH    = 1
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# https://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file or to the filename of jar file
+# to be used. If left blank, it is assumed PlantUML is not used or called during
+# a preprocessing step. Doxygen will generate a warning when it encounters a
+# \startuml command in this case and will not generate output for the diagram.
+
+PLANTUML_JAR_PATH      =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal
+# graphical representation for inheritance and collaboration diagrams is used.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
+# files that are used to generate the various graphs.
+#
+# Note: This setting is not only used for dot files but also for msc temporary
+# files.
+# The default value is: YES.
+
+DOT_CLEANUP            = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will
+# use a built-in version of mscgen tool to produce the charts. Alternatively,
+# the MSCGEN_TOOL tag can also specify the name an external tool. For instance,
+# specifying prog as the value, doxygen will call the tool as prog -T
+# <outfile_format> -o <outputfile> <inputfile>. The external tool should support
+# output file formats "png", "eps", "svg", and "ismap".
+
+MSCGEN_TOOL            =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =

+ 21 - 0
docs/index.md

@@ -0,0 +1,21 @@
+# libigl - A simple C++ geometry processing library
+
+This detailed documentation browser is automatically generated from the comments
+in libigl header (.h) files.
+
+In general, each function (e.g., `igl::func`) will be defined in a
+correspondingly named header file (e.g., `#include <igl/func.h>`).
+
+The _core_ library only depends on the standard template library (`std::`) and 
+Eigen. These functions reside directly the [`igl::` namespace](./namespaceigl.html)
+
+Functions with further dependencies reside in a corresonding sub-namespace. For
+example, the function `igl::spectra::lscm` depends on the Spectra library so it
+resides in the [`igl::spectra::` namespace](./namespaceigl_1_1spectra.html).
+
+Functions which depend on external code under a copyleft license reside in the
+[`igl::copyleft::` namepsace](file:///Users/alecjacobson/Repos/libigl/dox/namespaceigl_1_1copyleft.html).
+
+https://libigl.github.io/
+
+https://github.com/libigl/libigl/

+ 160 - 119
include/igl/AABB.h

@@ -15,35 +15,47 @@
 #include <vector>
 namespace igl
 {
-  // Implementation of semi-general purpose axis-aligned bounding box hierarchy.
-  // The mesh (V,Ele) is stored and managed by the caller and each routine here
-  // simply takes it as references (it better not change between calls).
-  //
-  // It's a little annoying that the Dimension is a template parameter and not
-  // picked up at run time from V. This leads to duplicated code for 2d/3d (up to
-  // dim).
+  /// Implementation of semi-general purpose axis-aligned bounding box hierarchy.
+  /// The mesh (V,Ele) is stored and managed by the caller and each routine here
+  /// simply takes it as references (it better not change between calls).
+  ///
+  /// It's a little annoying that the Dimension is a template parameter and not
+  /// picked up at run time from V. This leads to duplicated code for 2d/3d (up to
+  /// dim).
+  ///
+  /// @tparam DerivedV  Matrix type of vertex positions (e.g., `Eigen::MatrixXd`)
+  /// @tparam DIM Dimension of mesh vertex positions (2 or 3)
   template <typename DerivedV, int DIM>
     class AABB 
     {
 public:
+      /// Scalar type of vertex positions (e.g., `double`)
       typedef typename DerivedV::Scalar Scalar;
+      /// Fixed-size (`DIM`) RowVector type using `Scalar`
       typedef Eigen::Matrix<Scalar,1,DIM> RowVectorDIMS;
+      /// Fixed-size (`DIM`) (Column)Vector type using `Scalar`
       typedef Eigen::Matrix<Scalar,DIM,1> VectorDIMS;
+      /// Fixed-width (`DIM`) Matrix type using `Scalar`
       typedef Eigen::Matrix<Scalar,Eigen::Dynamic,DIM> MatrixXDIMS;
+      /// Pointer to "left" child node (`nullptr` if leaf)
       // Shared pointers are slower...
-      AABB * m_left;
+      AABB * m_left; 
+      /// Pointer to "right" child node (`nullptr` if leaf)
       AABB * m_right;
+      /// Axis-Aligned Bounding Box containing this node
       Eigen::AlignedBox<Scalar,DIM> m_box;
-      // -1 non-leaf
+      /// Index of single primitive in this node if full leaf, otherwise -1 for non-leaf
       int m_primitive;
       //Scalar m_low_sqr_d;
       //int m_depth;
+      /// @private
       AABB():
         m_left(NULL), m_right(NULL),
         m_box(), m_primitive(-1)
         //m_low_sqr_d(std::numeric_limits<double>::infinity()),
         //m_depth(0)
     {}
+      /// @private
       // http://stackoverflow.com/a/3279550/148668
       AABB(const AABB& other):
         m_left(other.m_left ? new AABB(*other.m_left) : NULL),
@@ -56,6 +68,7 @@ public:
         //   m_right ? m_right->m_depth + 1 : 0))
         {
         }
+      /// @private
       // copy-swap idiom
       friend void swap(AABB& first, AABB& second)
       {
@@ -68,18 +81,21 @@ public:
         //swap(first.m_low_sqr_d,second.m_low_sqr_d);
         //swap(first.m_depth,second.m_depth);
       }
+      /// @private
       // Pass-by-value (aka copy)
       AABB& operator=(AABB other)
       {
         swap(*this,other);
         return *this;
       }
+      /// @private
       AABB(AABB&& other):
         // initialize via default constructor
         AABB() 
       {
         swap(*this,other);
       }
+      /// @private
       // Seems like there should have been an elegant solution to this using
       // the copy-swap idiom above:
       IGL_INLINE void deinit()
@@ -91,20 +107,20 @@ public:
         delete m_right;
         m_right = NULL;
       }
+      /// @private
       ~AABB()
       {
         deinit();
       }
-      // Build an Axis-Aligned Bounding Box tree for a given mesh and given
-      // serialization of a previous AABB tree.
-      //
-      // Inputs:
-      //   V  #V by dim list of mesh vertex positions. 
-      //   Ele  #Ele by dim+1 list of mesh indices into #V. 
-      //   bb_mins  max_tree by dim list of bounding box min corner positions
-      //   bb_maxs  max_tree by dim list of bounding box max corner positions
-      //   elements  max_tree list of element or (not leaf id) indices into Ele
-      //   i  recursive call index {0}
+      /// Build an Axis-Aligned Bounding Box tree for a given mesh and given
+      /// serialization of a previous AABB tree.
+      ///
+      /// @param[in] V  #V by dim list of mesh vertex positions. 
+      /// @param[in] Ele  #Ele by dim+1 list of mesh indices into #V. 
+      /// @param[in] bb_mins  max_tree by dim list of bounding box min corner positions
+      /// @param[in] bb_maxs  max_tree by dim list of bounding box max corner positions
+      /// @param[in] elements  max_tree list of element or (not leaf id) indices into Ele
+      /// @param[in] i  recursive call index {0}
       template <
         typename DerivedEle, 
         typename Derivedbb_mins, 
@@ -117,43 +133,44 @@ public:
             const Eigen::MatrixBase<Derivedbb_maxs> & bb_maxs,
             const Eigen::MatrixBase<Derivedelements> & elements,
             const int i = 0);
-      // Wrapper for root with empty serialization
+      /// Build an Axis-Aligned Bounding Box tree for a given mesh and given
+      /// serialization of a previous AABB tree.
+      ///
+      /// @param[in] V  #V by dim list of mesh vertex positions. 
+      /// @param[in] Ele  #Ele by dim+1 list of mesh indices into #V. 
       template <typename DerivedEle>
       IGL_INLINE void init(
           const Eigen::MatrixBase<DerivedV> & V,
           const Eigen::MatrixBase<DerivedEle> & Ele);
-      // Build an Axis-Aligned Bounding Box tree for a given mesh.
-      //
-      // Inputs:
-      //   V  #V by dim list of mesh vertex positions. 
-      //   Ele  #Ele by dim+1 list of mesh indices into #V. 
-      //   SI  #Ele by dim list revealing for each coordinate where Ele's
-      //     barycenters would be sorted: SI(e,d) = i --> the dth coordinate of
-      //     the barycenter of the eth element would be placed at position i in a
-      //     sorted list.
-      //   I  #I list of indices into Ele of elements to include (for recursive
-      //     calls)
-      // 
+      /// Build an Axis-Aligned Bounding Box tree for a given mesh.
+      ///
+      /// @param[in] V  #V by dim list of mesh vertex positions. 
+      /// @param[in] Ele  #Ele by dim+1 list of mesh indices into #V. 
+      /// @param[in] SI  #Ele by dim list revealing for each coordinate where Ele's
+      ///              barycenters would be sorted: SI(e,d) = i --> the dth coordinate of
+      ///              the barycenter of the eth element would be placed at position i in a
+      ///              sorted list.
+      /// @param[in] I  #I list of indices into Ele of elements to include (for recursive
+      ///     calls)
+      /// 
       template <typename DerivedEle, typename DerivedSI, typename DerivedI>
       IGL_INLINE void init(
           const Eigen::MatrixBase<DerivedV> & V,
           const Eigen::MatrixBase<DerivedEle> & Ele, 
           const Eigen::MatrixBase<DerivedSI> & SI,
           const Eigen::MatrixBase<DerivedI>& I);
-      // Return whether at leaf node
+      /// Return whether at leaf node
       IGL_INLINE bool is_leaf() const;
-      // Find the indices of elements containing given point: this makes sense
-      // when Ele is a co-dimension 0 simplex (tets in 3D, triangles in 2D).
-      //
-      // Inputs:
-      //   V  #V by dim list of mesh vertex positions. **Should be same as used to
-      //     construct mesh.**
-      //   Ele  #Ele by dim+1 list of mesh indices into #V. **Should be same as used to
-      //     construct mesh.**
-      //   q  dim row-vector query position
-      //   first  whether to only return first element containing q
-      // Returns:
-      //   list of indices of elements containing q
+      /// Find the indices of elements containing given point: this makes sense
+      /// when Ele is a co-dimension 0 simplex (tets in 3D, triangles in 2D).
+      ///
+      /// @param[in]  V  #V by dim list of mesh vertex positions. **Should be same as used to
+      ///     construct mesh.**
+      /// @param[in]  Ele  #Ele by dim+1 list of mesh indices into #V. **Should be same as used to
+      ///     construct mesh.**
+      /// @param[in]  q  dim row-vector query position
+      /// @param[in]  first  whether to only return first element containing q
+      /// @return  list of indices of elements containing q
       template <typename DerivedEle, typename Derivedq>
       IGL_INLINE std::vector<int> find(
           const Eigen::MatrixBase<DerivedV> & V,
@@ -161,17 +178,18 @@ public:
           const Eigen::MatrixBase<Derivedq> & q,
           const bool first=false) const;
 
-      // If number of elements m then total tree size should be 2*h where h is
-      // the deepest depth 2^ceil(log(#Ele*2-1))
+      /// Number of nodes contained in subtree
+      ///
+      /// @return Number of elements m then total tree size should be 2*h where h is
+      /// the deepest depth 2^ceil(log(#Ele*2-1))
       IGL_INLINE int subtree_size() const;
 
-      // Serialize this class into 3 arrays (so we can pass it pack to matlab)
-      //
-      // Outputs:
-      //   bb_mins  max_tree by dim list of bounding box min corner positions
-      //   bb_maxs  max_tree by dim list of bounding box max corner positions
-      //   elements  max_tree list of element or (not leaf id) indices into Ele
-      //   i  recursive call index into these arrays {0}
+      /// Serialize this class into 3 arrays (so we can pass it pack to matlab)
+      ///
+      /// @param[out]  bb_mins  max_tree by dim list of bounding box min corner positions
+      /// @param[out]  bb_maxs  max_tree by dim list of bounding box max corner positions
+      /// @param[out]  elements  max_tree list of element or (not leaf id) indices into Ele
+      /// @param[in]  i  recursive call index into these arrays {0}
       template <
         typename Derivedbb_mins, 
         typename Derivedbb_maxs,
@@ -181,19 +199,17 @@ public:
             Eigen::PlainObjectBase<Derivedbb_maxs> & bb_maxs,
             Eigen::PlainObjectBase<Derivedelements> & elements,
             const int i = 0) const;
-      // Compute squared distance to a query point
-      //
-      // Inputs:
-      //   V  #V by dim list of vertex positions
-      //   Ele  #Ele by dim list of simplex indices
-      //   p  dim-long query point 
-      // Outputs:
-      //   i  facet index corresponding to smallest distances
-      //   c  closest point
-      // Returns squared distance
-      //
-      // Known bugs: currently assumes Elements are triangles regardless of
-      // dimension.
+      /// Compute squared distance to a query point
+      ///
+      /// @param[in]  V  #V by dim list of vertex positions
+      /// @param[in]  Ele  #Ele by dim list of simplex indices
+      /// @param[in]  p  dim-long query point 
+      /// @param[out]  i  facet index corresponding to smallest distances
+      /// @param[out]  c  closest point
+      /// @return squared distance
+      ///
+      /// \pre Currently assumes Elements are triangles regardless of
+      /// dimension.
       template <typename DerivedEle>
       IGL_INLINE Scalar squared_distance(
         const Eigen::MatrixBase<DerivedV> & V,
@@ -201,26 +217,23 @@ public:
         const RowVectorDIMS & p,
         int & i,
         Eigen::PlainObjectBase<RowVectorDIMS> & c) const;
-//private:
-      // Compute squared distance to a query point
-      //
-      // Inputs:
-      //   V  #V by dim list of vertex positions
-      //   Ele  #Ele by dim list of simplex indices
-      //   p  dim-long query point 
-      //   low_sqr_d  lower bound on squared distance, specified maximum squared
-      //     distance 
-      //   up_sqr_d  current upper bounded on squared distance, current minimum
-      //     squared distance (only consider distances less than this), see
-      //     output.
-      // Outputs:
-      //   up_sqr_d  updated current minimum squared distance
-      //   i  facet index corresponding to smallest distances
-      //   c  closest point
-      // Returns squared distance
-      //
-      // Known bugs: currently assumes Elements are triangles regardless of
-      // dimension.
+      /// Compute squared distance to a query point if within `low_sqr_d` and
+      /// `up_sqr_d`.
+      ///
+      /// @param[in] V  #V by dim list of vertex positions
+      /// @param[in] Ele  #Ele by dim list of simplex indices
+      /// @param[in] p  dim-long query point 
+      /// @param[in] low_sqr_d  lower bound on squared distance, specified maximum squared
+      ///              distance 
+      /// @param[in] up_sqr_d  current upper bounded on squared distance, current minimum
+      ///              squared distance (only consider distances less than this), see
+      ///              output.
+      /// @param[out]  i  facet index corresponding to smallest distances
+      /// @param[out]  c  closest point
+      /// @return squared distance
+      ///
+      /// \pre currently assumes Elements are triangles regardless of
+      /// dimension.
       template <typename DerivedEle>
       IGL_INLINE Scalar squared_distance(
         const Eigen::MatrixBase<DerivedV> & V,
@@ -230,7 +243,18 @@ public:
         const Scalar up_sqr_d,
         int & i,
         Eigen::PlainObjectBase<RowVectorDIMS> & c) const;
-      // Default low_sqr_d
+      /// Compute squared distance to a query point (default `low_sqr_d`)
+      ///
+      /// @param[in] V  #V by dim list of vertex positions
+      /// @param[in] Ele  #Ele by dim list of simplex indices
+      /// @param[in] p  dim-long query point 
+      /// @param[in] up_sqr_d  current upper bounded on squared distance, current minimum
+      ///              squared distance (only consider distances less than this), see
+      ///              output.
+      /// @param[out]  i  facet index corresponding to smallest distances
+      /// @param[out]  c  closest point
+      /// @return squared distance
+      ///
       template <typename DerivedEle>
       IGL_INLINE Scalar squared_distance(
         const Eigen::MatrixBase<DerivedV> & V,
@@ -239,7 +263,14 @@ public:
         const Scalar up_sqr_d,
         int & i,
         Eigen::PlainObjectBase<RowVectorDIMS> & c) const;
-      // All hits
+      /// Intersect a ray with the mesh return all hits
+      ///
+      /// @param[in]  V  #V by dim list of vertex positions
+      /// @param[in]  Ele  #Ele by dim list of simplex indices
+      /// @param[in]  origin  dim-long ray origin
+      /// @param[in]  dir  dim-long ray direction
+      /// @param[out]  hits  list of hits
+      /// @return  true if any hits
       template <typename DerivedEle>
       IGL_INLINE bool intersect_ray(
         const Eigen::MatrixBase<DerivedV> & V,
@@ -247,7 +278,14 @@ public:
         const RowVectorDIMS & origin,
         const RowVectorDIMS & dir,
         std::vector<igl::Hit> & hits) const;
-      // First hit
+      /// Intersect a ray with the mesh return first hit
+      ///
+      /// @param[in]  V  #V by dim list of vertex positions
+      /// @param[in]  Ele  #Ele by dim list of simplex indices
+      /// @param[in]  origin  dim-long ray origin
+      /// @param[in]  dir  dim-long ray direction
+      /// @param[out]  hit  first hit
+      /// @return  true if any hit
       template <typename DerivedEle>
       IGL_INLINE bool intersect_ray(
         const Eigen::MatrixBase<DerivedV> & V,
@@ -255,7 +293,15 @@ public:
         const RowVectorDIMS & origin,
         const RowVectorDIMS & dir,
         igl::Hit & hit) const;
-//private:
+      /// Intersect a ray with the mesh return first hit farther than `min_t`
+      ///
+      /// @param[in]  V  #V by dim list of vertex positions
+      /// @param[in]  Ele  #Ele by dim list of simplex indices
+      /// @param[in]  origin  dim-long ray origin
+      /// @param[in]  dir  dim-long ray direction
+      /// @param[in]  min_t  minimum t value to consider
+      /// @param[out]  hit  first hit
+      /// @return  true if any hit
       template <typename DerivedEle>
       IGL_INLINE bool intersect_ray(
         const Eigen::MatrixBase<DerivedV> & V,
@@ -265,20 +311,17 @@ public:
         const Scalar min_t,
         igl::Hit & hit) const;
 
-
 public:
-      // Compute the squared distance from all query points in P to the
-      // _closest_ points on the primitives stored in the AABB hierarchy for
-      // the mesh (V,Ele).
-      //
-      // Inputs:
-      //   V  #V by dim list of vertex positions
-      //   Ele  #Ele by dim list of simplex indices
-      //   P  #P by dim list of query points
-      // Outputs:
-      //   sqrD  #P list of squared distances
-      //   I  #P list of indices into Ele of closest primitives
-      //   C  #P by dim list of closest points
+      /// Compute the squared distance from all query points in P to the
+      /// _closest_ points on the primitives stored in the AABB hierarchy for
+      /// the mesh (V,Ele).
+      ///
+      /// @param[in] V  #V by dim list of vertex positions
+      /// @param[in] Ele  #Ele by dim list of simplex indices
+      /// @param[in] P  #P by dim list of query points
+      /// @param[out] sqrD  #P list of squared distances
+      /// @param[out] I  #P list of indices into Ele of closest primitives
+      /// @param[out] C  #P by dim list of closest points
       template <
         typename DerivedEle,
         typename DerivedP, 
@@ -293,21 +336,19 @@ public:
         Eigen::PlainObjectBase<DerivedI> & I,
         Eigen::PlainObjectBase<DerivedC> & C) const;
 
-      // Compute the squared distance from all query points in P already stored
-      // in its own AABB hierarchy to the _closest_ points on the primitives
-      // stored in the AABB hierarchy for the mesh (V,Ele).
-      //
-      // Inputs:
-      //   V  #V by dim list of vertex positions
-      //   Ele  #Ele by dim list of simplex indices
-      //   other  AABB hierarchy of another set of primitives (must be points)
-      //   other_V  #other_V by dim list of query points
-      //   other_Ele  #other_Ele by ss list of simplex indices into other_V
-      //     (must be simple list of points: ss == 1)
-      // Outputs:
-      //   sqrD  #P list of squared distances
-      //   I  #P list of indices into Ele of closest primitives
-      //   C  #P by dim list of closest points
+      /// Compute the squared distance from all query points in P already stored
+      /// in its own AABB hierarchy to the _closest_ points on the primitives
+      /// stored in the AABB hierarchy for the mesh (V,Ele).
+      ///
+      /// @param[in] V  #V by dim list of vertex positions
+      /// @param[in] Ele  #Ele by dim list of simplex indices
+      /// @param[in] other  AABB hierarchy of another set of primitives (must be points)
+      /// @param[in] other_V  #other_V by dim list of query points
+      /// @param[in] other_Ele  #other_Ele by ss list of simplex indices into other_V
+      ///     (must be simple list of points: ss == 1)
+      /// @param[out] sqrD  #P list of squared distances
+      /// @param[out] I  #P list of indices into Ele of closest primitives
+      /// @param[out] C  #P by dim list of closest points
       template < 
         typename DerivedEle,
         typename Derivedother_V,

+ 12 - 15
include/igl/ARAPEnergyType.h

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

+ 32 - 20
include/igl/AtA_cached.h

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

+ 16 - 5
include/igl/C_STR.h

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

+ 7 - 4
include/igl/Camera.h

@@ -22,10 +22,13 @@
 namespace igl
 {
 
-  // A simple camera class. The camera stores projection parameters (field of
-  // view angle, aspect ratio, near and far clips) as well as a rigid
-  // transformation *of the camera as if it were also a scene object*. Thus, the
-  // **inverse** of this rigid transformation is the modelview transformation.
+  /// A simple camera class. The camera stores projection parameters (field of
+  /// view angle, aspect ratio, near and far clips) as well as a rigid
+  /// transformation *of the camera as if it were also a scene object*. Thus, the
+  /// **inverse** of this rigid transformation is the modelview transformation.
+  ///
+  /// \deprecated This is not maintained.
+  /// @private
   class Camera
   {
     public:

+ 6 - 2
include/igl/EPS.h

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

+ 1 - 1
include/igl/FileEncoding.h

@@ -10,7 +10,7 @@
 
 namespace igl
 {
-
+  /// File encoding types for writing files.
 enum class FileEncoding {
   Binary,
   Ascii

+ 1 - 0
include/igl/FileMemoryStream.h

@@ -50,6 +50,7 @@ namespace igl {
     }
   };
   
+  /// Class to convert a FILE * to an std::istream
   struct FileMemoryStream : virtual FileMemoryBuffer, public std::istream 
   {
     FileMemoryStream( char const *first_elem, size_t size)

+ 48 - 44
include/igl/HalfEdgeIterator.h

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

+ 10 - 8
include/igl/Hit.h

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

+ 7 - 9
include/igl/IndexComparison.h

@@ -8,10 +8,8 @@
 #ifndef IGL_INDEXCOMPARISON_H
 #define IGL_INDEXCOMPARISON_H
 namespace igl{
-  // Comparison struct used by sort
-  // http://bytes.com/topic/c/answers/132045-sort-get-index
-
-  // For use with functions like std::sort
+  /// Comparison struct used by sort
+  /// http://bytes.com/topic/c/answers/132045-sort-get-index
   template<class T> struct IndexLessThan
   {
     IndexLessThan(const T arr) : arr(arr) {}
@@ -22,7 +20,7 @@ namespace igl{
     const T arr;
   };
 
-  // For use with functions like std::unique
+  /// Comparison struct used by unique
   template<class T> struct IndexEquals
   {
     IndexEquals(const T arr) : arr(arr) {}
@@ -33,7 +31,7 @@ namespace igl{
     const T arr;
   };
 
-  // For use with functions like std::sort
+  /// Comparison struct for vectors for use with functions like std::sort
   template<class T> struct IndexVectorLessThan
   {
     IndexVectorLessThan(const T & vec) : vec ( vec) {}
@@ -44,7 +42,7 @@ namespace igl{
     const T & vec;
   };
 
-  // For use with functions like std::sort
+  /// Comparison struct for use with functions like std::sort
   template<class T> struct IndexDimLessThan
   {
     IndexDimLessThan(const T & mat,const int & dim, const int & j) : 
@@ -67,7 +65,7 @@ namespace igl{
     const int & j;
   };
 
-  // For use with functions like std::sort
+  /// Comparison struct For use with functions like std::sort
   template<class T> struct IndexRowLessThan
   {
     IndexRowLessThan(const T & mat) : mat ( mat) {}
@@ -91,7 +89,7 @@ namespace igl{
     const T & mat;
   };
 
-  // For use with functions like std::sort
+  /// Comparison struct for use with functions like std::sort
   template<class T> struct IndexRowEquals
   {
     IndexRowEquals(const T & mat) : mat ( mat) {}

+ 34 - 25
include/igl/LinSpaced.h

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

+ 2 - 3
include/igl/MappingEnergyType.h

@@ -9,10 +9,9 @@
 #define IGL_MAPPINGENERGYTYPE_H
 namespace igl
 {
-  // Energy Types used for Parameterization/Mapping. 
-  // Refer to SLIM [Rabinovich et al. 2017] for more details
+  /// Energy Types used for Parameterization/Mapping. 
+  /// Refer to SLIM [Rabinovich et al. 2017] for more details
   // Todo: Integrate with ARAPEnergyType
-  
   enum MappingEnergyType
   {
     ARAP = 0,

+ 7 - 0
include/igl/MeshBooleanType.h

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

+ 5 - 3
include/igl/MshLoader.h

@@ -18,8 +18,8 @@
 
 namespace igl {
 
-// Class for loading information from .msh file
-// depends only on c++stl library
+/// Class for loading information from .msh file
+/// depends only on c++stl library
 class MshLoader {
     public:
 
@@ -60,6 +60,8 @@ class MshLoader {
               // other elements
               ELEMENT_POINT=15 };
     public:
+        /// Load a .msh file from a given path
+        /// @param[in] filename  path to .msh
         MshLoader(const std::string &filename);
 
     public:
@@ -187,4 +189,4 @@ class MshLoader {
 #  include "MshLoader.cpp"
 #endif
 
-#endif //IGL_MSH_LOADER_H
+#endif //IGL_MSH_LOADER_H

+ 6 - 3
include/igl/MshSaver.h

@@ -16,9 +16,9 @@
 
 namespace igl {
 
-// Class for dumping information to .msh file
-// depends only on c++stl library
-// current implementation works only with 3D information
+/// Class for dumping information to .msh file
+/// depends only on c++stl library
+/// current implementation works only with 3D information
 class MshSaver {
     public:
         typedef double Float;
@@ -30,6 +30,9 @@ class MshSaver {
         typedef std::vector<IntVector>   IntField;
         typedef std::vector<std::string> FieldNames;
 
+        /// Write a .msh to a given path
+        /// @param[in] filename  path to output file
+        /// @param[in] binary    whether to write in binary format
         MshSaver(const std::string& filename, bool binary=true);
         ~MshSaver();
 

+ 5 - 4
include/igl/NormalType.h

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

+ 3 - 3
include/igl/ONE.h

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

+ 2 - 0
include/igl/PI.h

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

+ 9 - 1
include/igl/REDRUM.h

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

+ 16 - 5
include/igl/STR.h

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

+ 5 - 3
include/igl/SolverStatus.h

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

+ 15 - 2
include/igl/SortableRow.h

@@ -14,16 +14,23 @@
 
 namespace igl
 {
-  // Templates:
-  //   T  should be a matrix that implements .size(), and operator(int i)
+  /// A row of things that can be sorted against other rows
+  /// @tparam T  should be a vector/matrix/array that implements .size(), and operator(int i)
   template <typename T>
   class SortableRow
   {
     public:
+      /// The data
       T data;
     public:
+      /// Default constructor
       SortableRow():data(){};
+      /// Constructor
+      /// @param[in] data  the data
       SortableRow(const T & data):data(data){};
+      /// Less than comparison
+      /// @param[in] that  the other row
+      /// @returns true if this row is less than that row
       bool operator<(const SortableRow & that) const
       {
         // Lexicographical
@@ -41,6 +48,9 @@ namespace igl
         // All characters the same, comes done to length
         return this->data.size()<that.data.size();
       };
+      /// Equality comparison
+      /// @param[in] that  the other row
+      /// @returns true if this row is equal to that row
       bool operator==(const SortableRow & that) const
       {
         if(this->data.size() != that.data.size())
@@ -56,6 +66,9 @@ namespace igl
         }
         return true;
       };
+      /// Inequality comparison
+      /// @param[in] that  the other row
+      /// @returns true if this row is not equal to that row
       bool operator!=(const SortableRow & that) const
       {
         return !(*this == that);

+ 16 - 8
include/igl/Timer.h

@@ -25,10 +25,11 @@
 
 namespace igl
 {
+  /// Simple timer class
   class Timer
   {
   public:
-    // default constructor
+    /// default constructor
     Timer():
       stopped(0),
 #ifdef WIN32
@@ -64,7 +65,10 @@ namespace igl
     }
 
 #ifdef __APPLE__
-    //Raw mach_absolute_times going in, difference in seconds out
+    /// Raw mach_absolute_times going in, difference in seconds out
+    /// @param[in] endTime   end time
+    /// @param[in] startTime start time
+    /// @return time
     double subtractTimes( uint64_t endTime, uint64_t startTime )
     {
       uint64_t difference = endTime - startTime;
@@ -84,7 +88,7 @@ namespace igl
     }
 #endif
 
-    // start timer
+    /// start timer
     void   start()               
     {
       stopped = 0; // reset stop flag
@@ -98,7 +102,7 @@ namespace igl
 
     }
 
-    // stop the timer
+    /// stop the timer
     void   stop()                
     {
       stopped = 1; // set timer stopped flag
@@ -112,23 +116,27 @@ namespace igl
 #endif
 
     }
-    // get elapsed time in second
+    /// get elapsed time in second
+    /// @return time in seconds
     double getElapsedTime()      
     {
       return this->getElapsedTimeInSec();
     }
-    // get elapsed time in second (same as getElapsedTime)
+    /// get elapsed time in second (same as getElapsedTime)
+    /// @return time
     double getElapsedTimeInSec() 
     {
       return this->getElapsedTimeInMicroSec() * 0.000001;
     }
 
-    // get elapsed time in milli-second
+    /// get elapsed time in milli-second
+    /// @return time
     double getElapsedTimeInMilliSec()
     {
       return this->getElapsedTimeInMicroSec() * 0.001;
     }
-    // get elapsed time in micro-second
+    /// get elapsed time in micro-second
+    /// @return time
     double getElapsedTimeInMicroSec()          
     {
       double startTimeInMicroSec = 0;

+ 1 - 0
include/igl/Viewport.h

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

+ 10 - 1
include/igl/WindingNumberAABB.h

@@ -16,6 +16,8 @@
 
 namespace igl
 {
+  /// Class for building an AABB tree to implement the divide and conquer
+  /// algorithm described in [Jacobson et al. 2013]. 
   template <
     typename Point,
     typename DerivedV, 
@@ -38,13 +40,20 @@ namespace igl
         total_positive_area(std::numeric_limits<typename DerivedV::Scalar>::infinity()),
         split_method(MEDIAN_ON_LONGEST_AXIS)
       {}
+      /// Constructor
+      ///
+      /// @param[in] V  #V by 3 list of vertex positions
+      /// @param[in] F  #F by 3 list of triangle indices into V
       inline WindingNumberAABB(
         const Eigen::MatrixBase<DerivedV> & V,
         const Eigen::MatrixBase<DerivedF> & F);
       inline WindingNumberAABB(
         const WindingNumberTree<Point,DerivedV,DerivedF> & parent,
         const Eigen::MatrixBase<DerivedF> & F);
-      // Initialize some things
+      /// Initialize the hierarchy to a given mesh
+      ///
+      /// @param[in] V  #V by 3 list of vertex positions
+      /// @param[in] F  #F by 3 list of triangle indices into V
       inline void set_mesh(
         const Eigen::MatrixBase<DerivedV> & V,
         const Eigen::MatrixBase<DerivedF> & F);

+ 4 - 3
include/igl/WindingNumberMethod.h

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

+ 3 - 4
include/igl/WindingNumberTree.h

@@ -14,10 +14,9 @@
 
 namespace igl
 {
-  // Space partitioning tree for computing winding number hierarchically.
-  //
-  // Templates:
-  //   Point  type for points in space, e.g. Eigen::Vector3d
+  /// Space partitioning tree for computing winding number hierarchically.
+  ///
+  /// @tparam Point  type for points in space, e.g. Eigen::Vector3d
   template <
     typename Point,
     typename DerivedV, 

+ 10 - 13
include/igl/accumarray.h

@@ -11,14 +11,11 @@
 #include <Eigen/Core>
 namespace igl
 {
-  // ACCUMARRY Like Matlab's accumarray. Accumulate values in V using subscripts
-  // in S.
-  //
-  // Inputs:
-  //   S  #S list of subscripts
-  //   V  #V list of values
-  // Outputs:
-  //   A  max(subs)+1 list of accumulated values
+  /// Accumulate values in V using subscripts in S. Like Matlab's accumarray. 
+  ///
+  /// @param[in] S  #S list of subscripts
+  /// @param[in] V  #V list of values
+  /// @param[out] A  max(subs)+1 list of accumulated values
   template <
     typename DerivedS,
     typename DerivedV,
@@ -28,11 +25,11 @@ namespace igl
     const Eigen::MatrixBase<DerivedS> & S,
     const Eigen::MatrixBase<DerivedV> & V,
     Eigen::PlainObjectBase<DerivedA> & A);
-  // Inputs:
-  //   S  #S list of subscripts
-  //   V  single value used for all
-  // Outputs:
-  //   A  max(subs)+1 list of accumulated values
+  /// Accumulate constant value `V` using subscripts in S. Like Matlab's accumarray. 
+  ///
+  /// @param[in] S  #S list of subscripts
+  /// @param[in] V  single value used for all
+  /// @param[out] A  max(subs)+1 list of accumulated values
   template <
     typename DerivedS,
     typename DerivedA

+ 47 - 42
include/igl/active_set.h

@@ -16,39 +16,41 @@
 namespace igl
 {
   struct active_set_params;
-  // Known Bugs: rows of [Aeq;Aieq] **must** be linearly independent. Should be
-  // using QR decomposition otherwise:
-  // https://v8doc.sas.com/sashtml/ormp/chap5/sect32.htm
-  //
-  // ACTIVE_SET Minimize quadratic energy 
-  //
-  // 0.5*Z'*A*Z + Z'*B + C with constraints
-  //
-  // that Z(known) = Y, optionally also subject to the constraints Aeq*Z = Beq,
-  // and further optionally subject to the linear inequality constraints that
-  // Aieq*Z <= Bieq and constant inequality constraints lx <= x <= ux
-  //
-  // Inputs:
-  //   A  n by n matrix of quadratic coefficients
-  //   B  n by 1 column of linear coefficients
-  //   known  list of indices to known rows in Z
-  //   Y  list of fixed values corresponding to known rows in Z
-  //   Aeq  meq by n list of linear equality constraint coefficients
-  //   Beq  meq by 1 list of linear equality constraint constant values
-  //   Aieq  mieq by n list of linear inequality constraint coefficients
-  //   Bieq  mieq by 1 list of linear inequality constraint constant values
-  //   lx  n by 1 list of lower bounds [] implies -Inf
-  //   ux  n by 1 list of upper bounds [] implies Inf
-  //   params  struct of additional parameters (see below)
-  //   Z  if not empty, is taken to be an n by 1 list of initial guess values
-  //     (see output)
-  // Outputs:
-  //   Z  n by 1 list of solution values
-  // Returns true on success, false on error
-  //
-  // Benchmark: For a harmonic solve on a mesh with 325K facets, matlab 2.2
-  // secs, igl/min_quad_with_fixed.h 7.1 secs
-  //
+  ///
+  /// Minimize convex quadratic energy subject to linear inequality constraints
+  ///
+  ///     min ½ Zᵀ A Z + Zᵀ B + constant
+  ///      Z
+  ///     subject to
+  ///            Aeq Z = Beq
+  ///            Aieq Z <= Bieq
+  ///            lx <= Z <= ux
+  ///            Z(known) = Y
+  ///
+  /// that Z(known) = Y, optionally also subject to the constraints Aeq*Z = Beq,
+  /// and further optionally subject to the linear inequality constraints that
+  /// Aieq*Z <= Bieq and constant inequality constraints lx <= x <= ux
+  ///
+  /// @param[in] A  n by n matrix of quadratic coefficients
+  /// @param[in] B  n by 1 column of linear coefficients
+  /// @param[in] known  list of indices to known rows in Z
+  /// @param[in] Y  list of fixed values corresponding to known rows in Z
+  /// @param[in] Aeq  meq by n list of linear equality constraint coefficients
+  /// @param[in] Beq  meq by 1 list of linear equality constraint constant values
+  /// @param[in] Aieq  mieq by n list of linear inequality constraint coefficients
+  /// @param[in] Bieq  mieq by 1 list of linear inequality constraint constant values
+  /// @param[in] lx  n by 1 list of lower bounds [] implies -Inf
+  /// @param[in] ux  n by 1 list of upper bounds [] implies Inf
+  /// @param[in] params  struct of additional parameters (see below)
+  /// @param[in,out] Z  if not empty, is taken to be an n by 1 list of initial guess values. Set to solution on output.
+  /// @return true on success, false on error
+  ///
+  /// \note Benchmark: For a harmonic solve on a mesh with 325K facets, matlab 2.2
+  /// secs, igl/min_quad_with_fixed.h 7.1 secs
+  ///
+  /// \pre rows of [Aeq;Aieq] **must** be linearly independent. Should be
+  /// using QR decomposition otherwise:
+  /// https://v8doc.sas.com/sashtml/ormp/chap5/sect32.htm
   template <
     typename AT, 
     typename DerivedB,
@@ -79,22 +81,25 @@ namespace igl
 };
 
 #include "EPS.h"
+/// Input parameters controling active_set
+///
+/// \fileinfo
 struct igl::active_set_params
 {
-  // Input parameters for active_set:
-  //   Auu_pd  whether Auu is positive definite {false}
-  //   max_iter  Maximum number of iterations (0 = Infinity, {100})
-  //   inactive_threshold  Threshold on Lagrange multiplier values to determine
-  //     whether to keep constraints active {EPS}
-  //   constraint_threshold  Threshold on whether constraints are violated (0
-  //     is perfect) {EPS}
-  //   solution_diff_threshold  Threshold on the squared norm of the difference
-  //     between two consecutive solutions {EPS}
+///  Auu_pd  whether Auu is positive definite {false}
   bool Auu_pd;
+///  max_iter  Maximum number of iterations (0 = Infinity, {100})
   int max_iter;
+///  inactive_threshold  Threshold on Lagrange multiplier values to determine
+///   whether to keep constraints active {EPS}
   double inactive_threshold;
+///  constraint_threshold  Threshold on whether constraints are violated (0
+///   is perfect) {EPS}
   double constraint_threshold;
+///  solution_diff_threshold  Threshold on the squared norm of the difference
+///    between two consecutive solutions {EPS}
   double solution_diff_threshold;
+  /// @private
   active_set_params():
     Auu_pd(false),
     max_iter(100),

+ 24 - 18
include/igl/adjacency_list.h

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

+ 34 - 33
include/igl/adjacency_matrix.h

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

+ 9 - 10
include/igl/all.h

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

+ 10 - 15
include/igl/all_pairs_distances.h

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

+ 32 - 16
include/igl/ambient_occlusion.h

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

+ 6 - 7
include/igl/angular_distance.h

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

+ 9 - 10
include/igl/any.h

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

+ 8 - 7
include/igl/any_of.h

@@ -10,13 +10,14 @@
 #include "igl_inline.h"
 namespace igl
 {
-  // Wrapper for STL `any_of` for matrix types
-  //
-  // Inputs:
-  //   S  matrix
-  // Returns whether any entries are true
-  //
-  // Seems that Eigen (now) implements this for `Eigen::Array` 
+  /// Wrapper for STL `any_of` for matrix types
+  ///
+  /// @param[in]  S  matrix
+  /// @return whether any entries are true
+  ///
+  /// \deprecated Seems that Eigen (now) implements this for `Eigen::Array` 
+  ///
+  /// \see any
   template <typename Mat>
   IGL_INLINE bool any_of(const Mat & S);
 }

+ 51 - 40
include/igl/arap.h

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

+ 136 - 134
include/igl/arap_dof.h

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

+ 65 - 30
include/igl/arap_linear_block.h

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

+ 13 - 14
include/igl/arap_rhs.h

@@ -15,20 +15,19 @@
 
 namespace igl
 {
-  // ARAP_RHS build right-hand side constructor of global poisson solve for
-  // various Arap energies
-  // Inputs:
-  //   V  #V by Vdim list of initial domain positions
-  //   F  #F by 3 list of triangle indices into V
-  //   dim  dimension being used at solve time. For deformation usually dim =
-  //     V.cols(), for surface parameterization V.cols() = 3 and dim = 2
-  //   energy  igl::ARAPEnergyType enum value defining which energy is being
-  //     used. See igl::ARAPEnergyType.h for valid options and explanations.
-  // Outputs:
-  //   K  #V*dim by #(F|V)*dim*dim matrix such that:
-  //     b = K * reshape(permute(R,[3 1 2]),size(V|F,1)*size(V,2)*size(V,2),1);
-  //
-  // See also: arap_linear_block
+  /// Right-hand side constructor of global poisson solve for various Arap
+  /// energies
+  ///
+  /// @param[in] V  #V by Vdim list of initial domain positions
+  /// @param[in] F  #F by 3 list of triangle indices into V
+  /// @param[in] dim  dimension being used at solve time. For deformation usually dim =
+  ///     V.cols(), for surface parameterization V.cols() = 3 and dim = 2
+  /// @param[in] energy  igl::ARAPEnergyType enum value defining which energy is being
+  ///     used. See igl::ARAPEnergyType.h for valid options and explanations.
+  /// @param[out] K  #V*dim by #(F|V)*dim*dim matrix such that:
+  ///     b = K * reshape(permute(R,[3 1 2]),size(V|F,1)*size(V,2)*size(V,2),1);
+  ///
+  /// \see arap_linear_block
   template<typename DerivedV, typename DerivedF, typename DerivedK>
   IGL_INLINE void arap_rhs(
     const Eigen::MatrixBase<DerivedV> & V,

+ 9 - 10
include/igl/average_from_edges_onto_vertices.h

@@ -12,16 +12,15 @@
 #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
+  /// Move a scalar field defined on edges to vertices by averaging
+  ///
+  /// @param[in] F #F by 3 triangle mesh connectivity
+  /// @param[in] E #E by 3 mapping from each halfedge to each edge
+  /// @param[in] oE #E by 3 orientation as generated by orient_halfedges
+  /// @param[in] uE #E by 1 list of scalars
+  /// @param[out] uV #V by 1 list of  scalar defined on vertices
+  ///
+  /// \see orient_halfedges
   template<typename DerivedF,typename DerivedE,typename DerivedoE,
   typename DeriveduE,typename DeriveduV>
   IGL_INLINE void average_from_edges_onto_vertices(

+ 5 - 7
include/igl/average_onto_faces.h

@@ -12,13 +12,11 @@
 #include <Eigen/Dense>
 namespace igl 
 {
-  // Move a scalar field defined on vertices to faces by averaging
-  //
-  // Input:
-  //   F  #F by ss list of simples/faces
-  //   S  #V by dim list of per-vertex values
-  // Output:
-  //   SF  #F by dim list of per-face values
+  /// Move a scalar field defined on vertices to faces by averaging
+  ///
+  /// @param[in] F  #F by ss list of simples/faces
+  /// @param[in] S  #V by dim list of per-vertex values
+  /// @param[out] SF  #F by dim list of per-face values
   template <typename DerivedF, typename DerivedS, typename DerivedSF>
   IGL_INLINE void average_onto_faces(
     const Eigen::MatrixBase<DerivedF> & F,

+ 6 - 9
include/igl/average_onto_vertices.h

@@ -12,15 +12,12 @@
 #include <Eigen/Dense>
 namespace igl
 {
-  // average_onto_vertices
-  // Move a scalar field defined on faces to vertices by averaging
-  //
-  // Input:
-  // V,F: mesh
-  // S: scalar field defined on faces, Fx1
-  //
-  // Output:
-  // SV: scalar field defined on vertices
+  /// Move a scalar field defined on faces to vertices by averaging
+  ///
+  /// @param[in] V #V by 3 list of mesh vertex positions
+  /// @param[in] F #F by 3 list of mesh face indices into rows of V
+  /// @param[in] S #F by 1 scalar field defined on faces
+  /// @param[out] SV #V by 1 scalar field defined on vertices
   template<typename DerivedV,typename DerivedF,typename DerivedS,typename DerivedSV>
   IGL_INLINE void average_onto_vertices(const Eigen::MatrixBase<DerivedV> &V,
     const Eigen::MatrixBase<DerivedF> &F,

+ 10 - 12
include/igl/avg_edge_length.h

@@ -15,18 +15,16 @@
 
 namespace igl
 {
-  // Compute the average edge length for the given triangle mesh
-  // Templates:
-  //   DerivedV derived from vertex positions matrix type: i.e. MatrixXd
-  //   DerivedF derived from face indices matrix type: i.e. MatrixXi
-  //   DerivedL derived from edge lengths matrix type: i.e. MatrixXd
-  // Inputs:
-  //   V  eigen matrix #V by 3
-  //   F  #F by simplex-size list of mesh faces (must be simplex)
-  // Outputs:
-  //   l  average edge length
-  //
-  // See also: adjacency_matrix
+  /// Compute the average edge length for the given triangle mesh
+  ///
+  /// @tparam DerivedV derived from vertex positions matrix type: i.e. MatrixXd
+  /// @tparam DerivedF derived from face indices matrix type: i.e. MatrixXi
+  /// @tparam DerivedL derived from edge lengths matrix type: i.e. MatrixXd
+  /// @param[in] V  #V by dim list of mesh vertex positions
+  /// @param[in] F  #F by simplex-size list of mesh faces (must be simplex)
+  /// @return average edge length
+  ///
+  /// \see adjacency_matrix
   template <typename DerivedV, typename DerivedF>
   IGL_INLINE double avg_edge_length(
     const Eigen::MatrixBase<DerivedV>& V,

+ 9 - 8
include/igl/axis_angle_to_quat.h

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

+ 6 - 8
include/igl/barycenter.h

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

+ 17 - 21
include/igl/barycentric_coordinates.h

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

+ 7 - 9
include/igl/barycentric_interpolation.h

@@ -11,15 +11,13 @@
 #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
+  /// Interpolate data on a triangle mesh using barycentric coordinates 
+  ///
+  /// @param[in] D  #D by dim list of per-vertex data
+  /// @param[in] F  #F by 3 list of triangle indices
+  /// @param[in] B  #X by 3 list of barycentric corodinates
+  /// @param[in] I  #X list of triangle indices
+  /// @param[out] X  #X by dim list of interpolated data
   template <
     typename DerivedD,
     typename DerivedF,

+ 8 - 6
include/igl/basename.h

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

+ 27 - 28
include/igl/bbw.h

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

+ 19 - 22
include/igl/bezier.h

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

+ 21 - 12
include/igl/bfs.h

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

+ 6 - 11
include/igl/bfs_orient.h

@@ -12,17 +12,12 @@
 
 namespace igl
 {
-  // Consistently orient faces in orientable patches using BFS
-  //
-  // F = bfs_orient(F,V);
-  //
-  // Inputs:
-  //  F  #F by 3 list of faces
-  // Outputs:
-  //  FF  #F by 3 list of faces (OK if same as F)
-  //  C  #F list of component ids
-  //
-  //
+  /// Consistently orient faces in orientable patches using BFS.
+  ///
+  /// @param[in] F  #F by 3 list of faces
+  /// @param[out] FF  #F by 3 list of faces (OK if same as F)
+  /// @param[out] C  #F list of component ids
+  ///
   template <typename DerivedF, typename DerivedFF, typename DerivedC>
   IGL_INLINE void bfs_orient(
     const Eigen::MatrixBase<DerivedF> & F,

+ 49 - 49
include/igl/biharmonic_coordinates.h

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

+ 27 - 31
include/igl/bijective_composite_harmonic_mapping.h

@@ -12,26 +12,24 @@
 
 namespace igl 
 {
-  // Compute a planar mapping of a triangulated polygon (V,F) subjected to
-  // boundary conditions (b,bc). The mapping should be bijective in the sense
-  // that no triangles' areas become negative (this assumes they started
-  // positive). This mapping is computed by "composing" harmonic mappings
-  // between incremental morphs of the boundary conditions. This is a bit like
-  // a discrete version of "Bijective Composite Mean Value Mappings" [Schneider
-  // et al. 2013] but with a discrete harmonic map (cf. harmonic coordinates)
-  // instead of mean value coordinates. This is inspired by "Embedding a
-  // triangular graph within a given boundary" [Xu et al. 2011].
-  //
-  // Inputs:
-  //   V  #V by 2 list of triangle mesh vertex positions
-  //   F  #F by 3 list of triangle indices into V
-  //   b  #b list of boundary indices into V
-  //   bc  #b by 2 list of boundary conditions corresponding to b
-  // Outputs:
-  //   U  #V by 2 list of output mesh vertex locations
-  // Returns true if and only if U contains a successful bijectie mapping
-  //
-  // 
+  /// Compute a injective planar mapping of a triangulated polygon (V,F) subjected to
+  /// boundary conditions (b,bc). The mapping should be bijective in the sense
+  /// that no triangles' areas become negative (this assumes they started
+  /// positive). This mapping is computed by "composing" harmonic mappings
+  /// between incremental morphs of the boundary conditions. This is a bit like
+  /// a discrete version of "Bijective Composite Mean Value Mappings" [Schneider
+  /// et al. 2013] but with a discrete harmonic map (cf. harmonic coordinates)
+  /// instead of mean value coordinates. This is inspired by "Embedding a
+  /// triangular graph within a given boundary" [Xu et al. 2011].
+  ///
+  /// @param[in] V  #V by 2 list of triangle mesh vertex positions
+  /// @param[in] F  #F by 3 list of triangle indices into V
+  /// @param[in] b  #b list of boundary indices into V
+  /// @param[in] bc  #b by 2 list of boundary conditions corresponding to b
+  /// @param[out] U  #V by 2 list of output mesh vertex locations
+  /// @return true if and only if U contains a successful bijectie mapping
+  ///
+  /// 
   template <
     typename DerivedV,
     typename DerivedF,
@@ -44,17 +42,15 @@ namespace igl
     const Eigen::MatrixBase<Derivedb> & b,
     const Eigen::MatrixBase<Derivedbc> & bc,
     Eigen::PlainObjectBase<DerivedU> & U);
-  //
-  // Inputs:
-  //   min_steps  minimum number of steps to take from V(b,:) to bc
-  //   max_steps  minimum number of steps to take from V(b,:) to bc (if
-  //     max_steps == min_steps then no further number of steps will be tried)
-  //   num_inner_iters  number of iterations of harmonic solves to run after
-  //     for each morph step (to try to push flips back in)
-  //   test_for_flips  whether to check if flips occurred (and trigger more
-  //     steps). if test_for_flips = false then this function always returns
-  //     true
-  // 
+  ///  \overload
+  ///  @param[in] min_steps  minimum number of steps to take from V(b,:) to bc
+  ///  @param[in] max_steps  minimum number of steps to take from V(b,:) to bc (if
+  ///     max_steps == min_steps then no further number of steps will be tried)
+  ///  @param[in] num_inner_iters  number of iterations of harmonic solves to run after
+  ///     for each morph step (to try to push flips back in)
+  ///  @param[in] test_for_flips  whether to check if flips occurred (and trigger more
+  ///     steps). if test_for_flips = false then this function always returns
+  ///     true
   template <
     typename DerivedV,
     typename DerivedF,

+ 10 - 9
include/igl/blkdiag.h

@@ -14,19 +14,20 @@
 
 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
+  /// Given a list of matrices place them along the diagonal as blocks of the
+  /// output matrix. Like matlab's blkdiag.
+  ///
+  /// @param[in] L  list of matrices {A,B, ...}
+  /// @param[out] Y  A.rows()+B.rows()+... by A.cols()+B.cols()+... block diagonal
+  ///
+  /// \see 
+  ///   cat, 
+  ///   repdiag
   template <typename Scalar>
   IGL_INLINE void blkdiag(
     const std::vector<Eigen::SparseMatrix<Scalar>> & L, 
     Eigen::SparseMatrix<Scalar> & Y);
+  /// \overload
   template <typename DerivedY>
   IGL_INLINE void blkdiag(
     const std::vector<DerivedY> & L, 

+ 14 - 16
include/igl/blue_noise.h

@@ -11,22 +11,20 @@
 #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
+  /// "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
+  ///
+  /// @param[in] V  #V by dim list of mesh vertex positions
+  /// @param[in] F  #F by 3 list of mesh triangle indices into rows of V
+  /// @param[in] r  Poisson disk radius (evaluated according to Euclidean distance on V)
+  /// @param[out] B  #P by 3 list of barycentric coordinates, ith row are coordinates of
+  ///               ith sampled point in face FI(i)
+  /// @param[out] FI  #P list of indices into F 
+  /// @param[out] P  #P by dim list of sample positions.
+  /// \see random_points_on_mesh
   template <
     typename DerivedV,
     typename DerivedF,

+ 4 - 7
include/igl/bone_parents.h

@@ -11,13 +11,10 @@
 #include <Eigen/Core>
 namespace igl
 {
-  // BONE_PARENTS Recover "parent" bones from directed graph representation.
-  // 
-  // Inputs:
-  //   BE  #BE by 2 list of directed bone edges
-  // Outputs:
-  //   P  #BE by 1 list of parent indices into BE, -1 means root.
-  //
+  /// Recover "parent" bones from directed graph representation.
+  /// 
+  /// @param[in] BE  #BE by 2 list of directed bone edges
+  /// @param[out] P  #BE by 1 list of parent indices into BE, -1 means root.
   template <typename DerivedBE, typename DerivedP>
   IGL_INLINE void bone_parents(
     const Eigen::MatrixBase<DerivedBE>& BE,

+ 24 - 25
include/igl/boundary_conditions.h

@@ -12,31 +12,30 @@
 
 namespace igl
 {
-
-  // Compute boundary conditions for automatic weights computation. This
-  // function expects that the given mesh (V,Ele) has sufficient samples
-  // (vertices) exactly at point handle locations and exactly along bone and
-  // cage edges.
-  //
-  // Inputs:
-  //   V  #V by dim list of domain vertices
-  //   Ele  #Ele by simplex-size list of simplex indices
-  //   C  #C by dim list of handle positions
-  //   P  #P by 1 list of point handle indices into C
-  //   BE  #BE by 2 list of bone edge indices into C
-  //   CE  #CE by 2 list of cage edge indices into *P*
-  // Outputs:
-  //   b  #b list of boundary indices (indices into V of vertices which have
-  //     known, fixed values)
-  //   bc #b by #weights list of known/fixed values for boundary vertices
-  //     (notice the #b != #weights in general because #b will include all the
-  //     intermediary samples along each bone, etc.. The ordering of the
-  //     weights corresponds to [P;BE]
-  // Returns false if boundary conditions are suspicious:
-  //   P and BE are empty
-  //   bc is empty
-  //   some column of bc doesn't have a 0 (assuming bc has >1 columns)
-  //   some column of bc doesn't have a 1 (assuming bc has >1 columns)
+  /// Compute boundary conditions for automatic weights computation. This
+  /// function expects that the given mesh (V,Ele) has sufficient samples
+  /// (vertices) exactly at point handle locations and exactly along bone and
+  /// cage edges.
+  ///
+  /// @param[in] V  #V by dim list of domain vertices
+  /// @param[in] Ele  #Ele by simplex-size list of simplex indices
+  /// @param[in] C  #C by dim list of handle positions
+  /// @param[in] P  #P by 1 list of point handle indices into C
+  /// @param[in] BE  #BE by 2 list of bone edge indices into C
+  /// @param[in] CE  #CE by 2 list of cage edge indices into *P*
+  /// @param[out] b  #b list of boundary indices (indices into V of vertices which have
+  ///     known, fixed values)
+  /// @param[out] bc #b by #weights list of known/fixed values for boundary vertices
+  ///     (notice the #b != #weights in general because #b will include all the
+  ///     intermediary samples along each bone, etc.. The ordering of the
+  ///     weights corresponds to [P;BE]
+  /// @return false if boundary conditions are suspicious:
+  ///   P and BE are empty
+  ///   bc is empty
+  ///   some column of bc doesn't have a 0 (assuming bc has >1 columns)
+  ///   some column of bc doesn't have a 1 (assuming bc has >1 columns)
+  ///
+  /// \note 3D cages are not yet supported.
   IGL_INLINE bool boundary_conditions(
     const Eigen::MatrixXd & V,
     const Eigen::MatrixXi & Ele,

+ 21 - 12
include/igl/boundary_facets.h

@@ -15,17 +15,14 @@
 
 namespace igl
 {
-  // BOUNDARY_FACETS Determine boundary faces (edges) of tetrahedra (triangles)
-  // stored in T (analogous to qptoolbox's `outline` and `boundary_faces`).
-  //
-  // Input:
-  //  T  tetrahedron (triangle) index list, m by 4 (3), where m is the number of tetrahedra
-  // Output:
-  //  F  list of boundary faces, n by 3 (2), where n is the number of boundary faces
-  //  J  list of indices into T, n by 1
-  //  K  list of indices revealing across from which vertex is this facet
-  //
-  //
+  /// Determine boundary faces (edges) of tetrahedra (triangles) stored in T
+  /// (analogous to qptoolbox's `outline` and `boundary_faces`).
+  ///
+  /// @param[in] T  tetrahedron (triangle) index list, m by 4 (3), where m is the number of tetrahedra
+  /// @param[out] F  list of boundary faces, n by 3 (2), where n is the number of boundary faces
+  /// @param[out] J  list of indices into T, n by 1
+  /// @param[out] K  list of indices revealing across from which vertex is this facet
+  ///
   template <
     typename DerivedT, 
     typename DerivedF,
@@ -36,14 +33,26 @@ namespace igl
     Eigen::PlainObjectBase<DerivedF>& F,
     Eigen::PlainObjectBase<DerivedJ>& J,
     Eigen::PlainObjectBase<DerivedK>& K);
+  /// Determine boundary faces (edges) of tetrahedra (triangles) stored in T.
+  ///
+  /// @param[in] T  tetrahedron (triangle) index list, m by 4 (3), where m is the number of tetrahedra
+  /// @param[out] F  list of boundary faces, n by 3 (2), where n is the number of boundary faces
   template <typename DerivedT, typename DerivedF>
   IGL_INLINE void boundary_facets(
     const Eigen::MatrixBase<DerivedT>& T,
     Eigen::PlainObjectBase<DerivedF>& F);
-  // Same as above but returns F
+  /// Determine boundary faces (edges) of tetrahedra (triangles) stored in T.
+  ///
+  /// @param[in] T  tetrahedron (triangle) index list, m by 4 (3), where m is the number of tetrahedra
+  /// @return list of boundary faces, n by 3 (2), where n is the number of boundary faces
   template <typename DerivedT, typename Ret>
   Ret boundary_facets(
     const Eigen::MatrixBase<DerivedT>& T);
+  /// Determine boundary faces (edges) of tetrahedra (triangles) stored in T;
+  /// inputs and outputs lists.
+  ///
+  /// @param[in] T  tetrahedron (triangle) index list, m by 4 (3), where m is the number of tetrahedra
+  /// @param[out] F  list of boundary faces, n by 3 (2), where n is the number of boundary faces
   template <typename IntegerT, typename IntegerF>
   IGL_INLINE void boundary_facets(
     const std::vector<std::vector<IntegerT> > & T,

+ 20 - 30
include/igl/boundary_loop.h

@@ -14,46 +14,36 @@
 
 namespace igl
 {
-  // Compute list of ordered boundary loops for a manifold mesh.
-  //
-  // Templates:
-  //  Index  index type
-  // Inputs:
-  //   F  #V by dim list of mesh faces
-  // Outputs:
-  //   L  list of loops where L[i] = ordered list of boundary vertices in loop i
-  //
+  /// Compute list of ordered boundary loops for a manifold mesh.
+  ///
+  /// @tparam Index  index type
+  /// @param[in] F  #F by dim list of mesh faces
+  /// @param[out] L  list of loops where L[i] = ordered list of boundary vertices in loop i
+  ///
   template <typename DerivedF, typename Index>
   IGL_INLINE void boundary_loop(
     const Eigen::MatrixBase<DerivedF>& F, 
     std::vector<std::vector<Index> >& L);
 
 
-  // Compute ordered boundary loops for a manifold mesh and return the 
-  // longest loop in terms of vertices.
-  //
-  // Templates:
-  //  Index  index type
-  // Inputs:
-  //   F  #V by dim list of mesh faces
-  // Outputs:
-  //   L  ordered list of boundary vertices of longest boundary loop
-  //
+  /// Compute ordered boundary loops for a manifold mesh and return the 
+  /// longest loop in terms of vertices.
+  ///
+  /// @tparam Index  index type
+  /// @param[in] F  #F by dim list of mesh faces
+  /// @param[out]  L  ordered list of boundary vertices of longest boundary loop
+  ///
   template <typename DerivedF, typename Index>
   IGL_INLINE void boundary_loop(
     const Eigen::MatrixBase<DerivedF>& F, 
     std::vector<Index>& L);
-
-  // Compute ordered boundary loops for a manifold mesh and return the 
-  // longest loop in terms of vertices.
-  //
-  // Templates:
-  //  Index  index type
-  // Inputs:
-  //   F  #V by dim list of mesh faces
-  // Outputs:
-  //   L  ordered list of boundary vertices of longest boundary loop
-  //
+  /// Compute ordered boundary loops for a manifold mesh and return the 
+  /// longest loop in terms of vertices.
+  ///
+  /// @tparam Index  index type
+  /// @param[in] F  #F by dim list of mesh faces
+  /// @param[out]  L  ordered list of boundary vertices of longest boundary loop
+  ///
   template <typename DerivedF, typename DerivedL>
   IGL_INLINE void boundary_loop(
     const Eigen::MatrixBase<DerivedF>& F, 

+ 8 - 7
include/igl/bounding_box.h

@@ -11,18 +11,19 @@
 #include <Eigen/Core>
 namespace igl
 {
-  // Build a triangle mesh of the bounding box of a given list of vertices
-  // 
-  // Inputs:
-  //   V  #V by dim list of rest domain positions
-  // Outputs:
-  //   BV  2^dim by dim list of bounding box corners positions
-  //   BF  #BF by dim list of simplex facets 
+  /// Build a triangle mesh of the bounding box of a given list of vertices
+  /// 
+  /// @param[in]  V  #V by dim list of rest domain positions
+  /// @param[out] BV  2^dim by dim list of bounding box corners positions
+  /// @param[out] BF  #BF by dim list of simplex facets 
   template <typename DerivedV, typename DerivedBV, typename DerivedBF>
   IGL_INLINE void bounding_box(
     const Eigen::MatrixBase<DerivedV>& V,
     Eigen::PlainObjectBase<DerivedBV>& BV,
     Eigen::PlainObjectBase<DerivedBF>& BF);
+  /// \overload \brief With padding.
+  /// 
+  /// @param[in]  pad  padding offset
   template <typename DerivedV, typename DerivedBV, typename DerivedBF>
   IGL_INLINE void bounding_box(
     const Eigen::MatrixBase<DerivedV>& V,

+ 5 - 6
include/igl/bounding_box_diagonal.h

@@ -11,12 +11,11 @@
 #include <Eigen/Dense>
 namespace igl
 {
-  // Compute the length of the diagonal of a given meshes axis-aligned bounding
-  // box
-  //
-  // Inputs:
-  //   V  #V by 3 list of vertex/point positions
-  // Returns length of bounding box diagonal
+  /// Compute the length of the diagonal of a given meshes axis-aligned bounding
+  /// box.
+  ///
+  /// @param[in] V  #V by 3 list of vertex/point positions
+  /// @return length of bounding box diagonal
   IGL_INLINE double bounding_box_diagonal( const Eigen::MatrixXd & V);
 }
 

+ 9 - 4
include/igl/canonical_quaternions.h

@@ -8,14 +8,19 @@
 #ifndef IGL_CANONICAL_QUATERNIONS_H
 #define IGL_CANONICAL_QUATERNIONS_H
 #include "igl_inline.h"
-// Define some canonical quaternions for floats and doubles
-// A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w),
-// such that q = x*i + y*j + z*k + w
+/// @file canonical_quaternions
+///
+/// Define some canonical quaternions for floats and doubles
+/// A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w),
+/// such that q = x*i + y*j + z*k + w.
+///
+/// \see snap_to_canonical_view_quat
 namespace igl
 {
   // Float versions
+  // This will get undef'd below
 #define SQRT_2_OVER_2 0.707106781f
-  // Identity
+  // Identity quaternion
   const float IDENTITY_QUAT_F[4] = {0,0,0,1};
   // The following match the Matlab canonical views
   // X point right, Y pointing up and Z point out

+ 42 - 39
include/igl/cat.h

@@ -16,61 +16,64 @@
 
 namespace igl
 {
-  // If you're using Dense matrices you might be better off using the << operator
-
-  // This is an attempt to act like matlab's cat function.
-
-  // Perform concatenation of a two matrices along a single dimension
-  // If dim == 1, then C = [A;B]. If dim == 2 then C = [A B]
-  // 
-  // Template:
-  //   Scalar  scalar data type for sparse matrices like double or int
-  //   Mat  matrix type for all matrices (e.g. MatrixXd, SparseMatrix)
-  //   MatC  matrix type for output matrix (e.g. MatrixXd) needs to support
-  //     resize
-  // Inputs:
-  //   A  first input matrix
-  //   B  second input matrix
-  //   dim  dimension along which to concatenate, 1 or 2
-  // Outputs:
-  //   C  output matrix
-  //   
+  /// Perform concatenation of a two _sparse_ matrices along a single dimension
+  /// If dim == 1, then C = [A;B]; If dim == 2 then C = [A B].
+  /// This is an attempt to act like matlab's cat function.
+  /// 
+  /// @tparam  Scalar  scalar data type for sparse matrices like double or int
+  /// @tparam  Mat  matrix type for all matrices (e.g. MatrixXd, SparseMatrix)
+  /// @tparam  MatC  matrix type for output matrix (e.g. MatrixXd) needs to support
+  ///     resize
+  /// @param[in]  dim  dimension along which to concatenate, 1 or 2
+  /// @param[in]  A  first input matrix
+  /// @param[in]  B  second input matrix
+  /// @param[out]  C  output matrix
+  ///   
   template <typename Scalar>
   IGL_INLINE void cat(
       const int dim, 
       const Eigen::SparseMatrix<Scalar> & A, 
       const Eigen::SparseMatrix<Scalar> & B, 
       Eigen::SparseMatrix<Scalar> & C);
+
+  /// Perform concatenation of a two _dense_ matrices along a single dimension
+  /// If dim == 1, then C = [A;B]; If dim == 2 then C = [A B].
+  ///
+  /// @param[in]  dim  dimension along which to concatenate, 1 or 2
+  /// @param[in]  A  first input matrix
+  /// @param[in]  B  second input matrix
+  /// @param[out]  C  output matrix
+  ///
+  /// \note If you're using Dense matrices you might be better off using the << operator
   template <typename Derived, class MatC>
   IGL_INLINE void cat(
     const int dim,
     const Eigen::MatrixBase<Derived> & A, 
     const Eigen::MatrixBase<Derived> & B,
     MatC & C);
-  // Wrapper that returns C
+  /// Perform concatenation of a two _dense_ matrices along a single dimension
+  /// If dim == 1, then C = [A;B]; If dim == 2 then C = [A B].
+  ///
+  /// @param[in]  dim  dimension along which to concatenate, 1 or 2
+  /// @param[in]  A  first input matrix
+  /// @param[in]  B  second input matrix
+  /// @return C  output matrix
+  ///
+  /// \note If you're using Dense matrices you might be better off using the << operator
   template <class Mat>
   IGL_INLINE Mat cat(const int dim, const Mat & A, const Mat & B);
-
-  // Note: Maybe we can autogenerate a bunch of overloads D = cat(int,A,B,C),
-  // E = cat(int,A,B,C,D), etc. 
-
-  // Concatenate a "matrix" of blocks
-  // C = [A0;A1;A2;...;An] where Ai = [A[i][0] A[i][1] ... A[i][m]];
-  //
-  // Inputs:
-  //   A  a matrix (vector of row vectors)
-  // Output:
-  //   C
+  /// Concatenate a "matrix" of sub-blocks
+  /// C = [A0;A1;A2;...;An] where Ai = [A[i][0] A[i][1] ... A[i][m]];
+  ///
+  /// @param[in]  A  a list of list of matrices (sizes must be compatibile)
+  /// @param[out]  C output matrix
   template <class Mat>
   IGL_INLINE void cat(const std::vector<std::vector< Mat > > & A, Mat & C);
-
-  // Concatenate a std::vector of matrices along the specified dimension
-  //
-  // Inputs:
-  //   dim  dimension along which to concatenate, 1 or 2
-  //   A  std::vector of eigen matrices. Must have identical # cols if dim == 1 or rows if dim == 2
-  // Outputs:
-  //   C  output matrix
+  /// Concatenate a std::vector of matrices along the specified dimension
+  ///
+  /// @param[in] dim  dimension along which to concatenate, 1 or 2
+  /// @param[in] A  std::vector of eigen matrices. Must have identical # cols if dim == 1 or rows if dim == 2
+  /// @param[out] C  output matrix
   template <typename T, typename DerivedC>
   IGL_INLINE void cat(const int dim, const std::vector<T> & A, Eigen::PlainObjectBase<DerivedC> & C);
 }

+ 4 - 6
include/igl/ceil.h

@@ -11,12 +11,10 @@
 #include <Eigen/Dense>
 namespace igl
 {
-  // Ceil a given matrix to nearest integers 
-  //
-  // Inputs:
-  //   X  m by n matrix of scalars
-  // Outputs:
-  //   Y  m by n matrix of ceiled integers
+  /// Ceil a given matrix to nearest integers 
+  ///
+  /// @param[in] X  m by n matrix of scalars
+  /// @param[out] Y  m by n matrix of ceiled integers
   template < typename DerivedX, typename DerivedY>
   IGL_INLINE void ceil(
     const Eigen::PlainObjectBase<DerivedX>& X,

+ 8 - 9
include/igl/centroid.h

@@ -11,15 +11,13 @@
 #include <Eigen/Core>
 namespace igl
 {
-  // CENTROID Computes the centroid of a closed mesh using a surface integral.
-  // 
-  // Inputs:
-  //   V  #V by dim list of rest domain positions
-  //   F  #F by 3 list of triangle indices into V
-  // Outputs:
-  //    c  dim vector of centroid coordinates
-  //    vol  total volume of solid.
-  //
+  /// Computes the centroid and enclosed volume of a closed mesh using a surface integral.
+  /// 
+  /// @param[in] V  #V by dim list of rest domain positions
+  /// @param[in] F  #F by 3 list of triangle indices into V
+  /// @param[out]   c  dim vector of centroid coordinates
+  /// @param[out]   vol  total volume of solid.
+  ///
   template <
     typename DerivedV, 
     typename DerivedF, 
@@ -30,6 +28,7 @@ namespace igl
     const Eigen::MatrixBase<DerivedF>& F,
     Eigen::PlainObjectBase<Derivedc>& c,
     Derivedvol & vol);
+  /// \overload
   template <
     typename DerivedV, 
     typename DerivedF, 

+ 46 - 21
include/igl/circulation.h

@@ -13,29 +13,42 @@
 
 namespace igl
 {
-  // Return list of faces around the end point of an edge. Assumes
-  // data-structures are built from an edge-manifold **closed** mesh.
-  //
-  // Inputs:
-  //   e  index into E of edge to circulate
-  //   ccw  whether to _continue_ in ccw direction of edge (circulate around
-  //     E(e,1))
-  //   EMAP #F*3 list of indices into E, mapping each directed edge to unique
-  //     unique edge in E
-  //   EF  #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of
-  //     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).
-  // Returns list of faces touched by circulation (in cyclically order).
-  //   
-  // See also: edge_flaps
+  /// Return list of faces around the end point of an edge. Assumes
+  /// data-structures are built from an edge-manifold **closed** mesh.
+  ///
+  /// @param[in] e  index into E of edge to circulate
+  /// @param[in] ccw  whether to _continue_ in ccw direction of edge (circulate around
+  ///     E(e,1))
+  /// @param[in] EMAP #F*3 list of indices into E, mapping each directed edge to unique
+  ///     unique edge in E
+  /// @param[in] EF  #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of
+  ///     F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1) "
+  ///     e=(j->i)
+  /// @param[in] EI  #E by 2 list of edge flap corners (see above).
+  /// @return list of faces touched by circulation (in cyclically order).
+  ///   
+  /// \see edge_flaps
   IGL_INLINE std::vector<int> circulation(
     const int e,
     const bool ccw,
     const Eigen::VectorXi & EMAP,
     const Eigen::MatrixXi & EF,
     const Eigen::MatrixXi & EI);
-  // Wrapper with VectorXi output.
+  /// Return list of faces around the end point of an edge. Assumes
+  /// data-structures are built from an edge-manifold **closed** mesh.
+  ///
+  /// @param[in] e  index into E of edge to circulate
+  /// @param[in] ccw  whether to _continue_ in ccw direction of edge (circulate around
+  ///     E(e,1))
+  /// @param[in] EMAP #F*3 list of indices into E, mapping each directed edge to unique
+  ///     unique edge in E
+  /// @param[in] EF  #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of
+  ///     F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1) "
+  ///     e=(j->i)
+  /// @param[in] EI  #E by 2 list of edge flap corners (see above).
+  /// @param[out] #vN list of of faces touched by circulation (in cyclically order).
+  ///   
+  /// \see edge_flaps
   IGL_INLINE void circulation(
     const int e,
     const bool ccw,
@@ -43,10 +56,22 @@ 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
+  /// Return list of faces around the end point of an edge. Assumes
+  /// data-structures are built from an edge-manifold **closed** mesh.
+  ///
+  /// @param[in] e  index into E of edge to circulate
+  /// @param[in] ccw  whether to _continue_ in ccw direction of edge (circulate around
+  ///     E(e,1))
+  /// @param[in] EMAP #F*3 list of indices into E, mapping each directed edge to unique
+  ///     unique edge in E
+  /// @param[in] EF  #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of
+  ///     F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1) "
+  ///     e=(j->i)
+  /// @param[in] EI  #E by 2 list of edge flap corners (see above).
+  ///  @param[out] Nv  #Nv list of "next" vertex indices
+  ///  @param[out] Nf  #Nf list of face indices
+  ///   
+  /// \see edge_flaps
   IGL_INLINE void circulation(
     const int e,
     const bool ccw,

+ 6 - 8
include/igl/circumradius.h

@@ -11,14 +11,12 @@
 #include <Eigen/Core>
 namespace igl
 {
-  // Compute the circumradius of each triangle in a mesh (V,F)
-  //
-  // Inputs:
-  //   V  #V by dim list of mesh vertex positions
-  //   F  #F by 3 list of triangle indices into V
-  // Outputs:
-  //   R  #F list of circumradius
-  //
+  /// Compute the circumradius of each triangle in a mesh (V,F)
+  ///
+  /// @param[in] V  #V by dim list of mesh vertex positions
+  /// @param[in] F  #F by 3 list of triangle indices into V
+  /// @param[out] R  #F list of circumradius
+  ///
   template <
     typename DerivedV, 
     typename DerivedF,

+ 86 - 65
include/igl/collapse_edge.h

@@ -15,35 +15,39 @@
 #include <set>
 namespace igl
 {
-  // Assumes (V,F) is a closed manifold mesh (except for previously collapsed
-  // faces which should be set to: 
-  // [IGL_COLLAPSE_EDGE_NULL IGL_COLLAPSE_EDGE_NULL IGL_COLLAPSE_EDGE_NULL].
-  // Collapses exactly two faces and exactly 3 edges from E (e and one side of
-  // each face gets collapsed to the other). This is implemented in a way that
-  // it can be repeatedly called until satisfaction and then the garbage in F
-  // can be collected by removing NULL faces.
-  //
-  // Inputs:
-  //   e  index into E of edge to try to collapse. E(e,:) = [s d] or [d s] so
-  //     that s<d, then d is collapsed to s.
-  ///  p  dim list of vertex position where to place merged vertex
-  // Inputs/Outputs:
-  //   V  #V by dim list of vertex positions, lesser index of E(e,:) will be set
-  //     to midpoint of edge.
-  //   F  #F by 3 list of face indices into V.
-  //   E  #E by 2 list of edge indices into V.
-  //   EMAP #F*3 list of indices into E, mapping each directed edge to unique
-  //     unique edge in E
-  //   EF  #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of
-  //     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).
-  //   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
-  // Returns true if edge was collapsed
+#ifndef IGL_COLLAPSE_EDGE_NULL
+  /// Special value for indicating a null vertex index as the result of a
+  /// collapsed edge.
   #define IGL_COLLAPSE_EDGE_NULL 0
+#endif
+  /// Attempt to collapse a given edge of a mesh. Assumes (V,F) is a closed
+  /// manifold mesh (except for previously collapsed faces which should be set
+  /// to: [IGL_COLLAPSE_EDGE_NULL IGL_COLLAPSE_EDGE_NULL
+  /// IGL_COLLAPSE_EDGE_NULL]. Collapses exactly two faces and exactly 3 edges
+  /// from E (e and one side of each face gets collapsed to the other). This is
+  /// implemented in a way that it can be repeatedly called until satisfaction
+  /// and then the garbage in F can be collected by removing NULL faces.
+  ///
+  /// @param[in] e  index into E of edge to try to collapse. E(e,:) = [s d] or [d s] so
+  ///     that s<d, then d is collapsed to s.
+  /// @param[in] p  dim list of vertex position where to place merged vertex
+  /// [mesh inputs]
+  /// @param[in,out] V  #V by dim list of vertex positions, lesser index of E(e,:) will be set
+  ///     to midpoint of edge.
+  /// @param[in,out] F  #F by 3 list of face indices into V.
+  /// @param[in,out] E  #E by 2 list of edge indices into V.
+  /// @param[in,out] EMAP #F*3 list of indices into E, mapping each directed edge to unique
+  ///     unique edge in E
+  /// @param[in,out] EF  #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of
+  ///     F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1) "
+  ///     e=(j->i)
+  /// @param[in,out] EI  #E by 2 list of edge flap corners (see above).
+  /// [mesh inputs]
+  /// @param[out] e1  index into E of edge collpased on left
+  /// @param[out] e2  index into E of edge collpased on right
+  /// @param[out] f1  index into F of face collpased on left
+  /// @param[out] f2  index into F of face collpased on right
+  /// @return true if edge was collapsed
   IGL_INLINE bool collapse_edge(
     const int e,
     const Eigen::RowVectorXd & p,
@@ -57,7 +61,12 @@ namespace igl
     int & e2,
     int & f1,
     int & f2);
-  // Inputs:
+  /// \overload
+  ///
+  /// @param[in] Nsv #Nsv vertex circulation around s (see circulation)
+  /// @param[in] Nsf #Nsf face circulation around s
+  /// @param[in] Ndv #Ndv vertex circulation around d
+  /// @param[in] Ndf #Ndf face circulation around d
   IGL_INLINE bool collapse_edge(
     const int e,
     const Eigen::RowVectorXd & p,
@@ -75,6 +84,7 @@ namespace igl
     int & e2,
     int & f1,
     int & f2);
+  /// \overload
   IGL_INLINE bool collapse_edge(
     const int e,
     const Eigen::RowVectorXd & p,
@@ -84,20 +94,46 @@ namespace igl
     Eigen::VectorXi & EMAP,
     Eigen::MatrixXi & EF,
     Eigen::MatrixXi & EI);
-  // Collapse least-cost edge from a priority queue and update queue 
-  //
-  // Inputs/Outputs:
-  //   cost_and_placement  function computing cost of collapsing an edge and 3d
-  //     position where it should be placed:
-  //     cost_and_placement(V,F,E,EMAP,EF,EI,cost,placement);
-  //     **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 and insertion "time"
-  //   EQ  #E list of "time" of last time pushed into Q
-  //   C  #E by dim list of stored placements
+  /// Collapse least-cost edge from a priority queue and update queue 
+  ///
+  /// See decimate.h for more details.
+  ///
+  /// @param[in] cost_and_placement  function computing cost of collapsing an edge and 3d
+  ///     position where it should be placed:
+  ///     cost_and_placement(V,F,E,EMAP,EF,EI,cost,placement);
+  ///     **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.
+  ///  @param[in] pre_collapse  callback called with index of edge whose collapse is about
+  ///     to be attempted. This function should return whether to **proceed**
+  ///     with the collapse: returning true means "yes, try to collapse",
+  ///     returning false means "No, consider this edge 'uncollapsable', behave
+  ///     as if collapse_edge(e) returned false.
+  ///  @param[in] post_collapse  callback called with index of edge whose collapse was
+  ///     just attempted and a flag revealing whether this was successful.
+  /// @param[in,out] V  #V by dim list of vertex positions, lesser index of E(e,:) will be set
+  ///     to midpoint of edge.
+  /// @param[in,out] F  #F by 3 list of face indices into V.
+  /// @param[in,out] E  #E by 2 list of edge indices into V.
+  /// @param[in,out] EMAP #F*3 list of indices into E, mapping each directed edge to unique
+  ///     unique edge in E
+  /// @param[in,out] EF  #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of
+  ///     F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1)
+  ///     e=(j->i)
+  /// @param[in,out] EI  #E by 2 list of edge flap corners (see above).
+  /// @param[in] Q  queue containing pairs of costs and edge indices and insertion "time"
+  /// @param[in] EQ  #E list of "time" of last time pushed into Q
+  /// @param[in] C  #E by dim list of stored placements
+  /// @param[out] e  index into E of attempted collapsed edge. Set to -1 if Q is empty or
+  ///               contains only infinite cost edges.
+  /// @param[out] e1  index into E of edge collpased on left.
+  /// @param[out] e2  index into E of edge collpased on right.
+  /// @param[out] f1  index into F of face collpased on left.
+  /// @param[out] f2  index into F of face collpased on right.
   IGL_INLINE bool collapse_edge(
     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,
@@ -106,19 +142,15 @@ namespace igl
     Eigen::MatrixXi & EI,
     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
-  //     to be attempted. This function should return whether to **proceed**
-  //     with the collapse: returning true means "yes, try to collapse",
-  //     returning false means "No, consider this edge 'uncollapsable', behave
-  //     as if collapse_edge(e) returned false.
-  //   post_collapse  callback called with index of edge whose collapse was
-  //     just attempted and a flag revealing whether this was successful.
+    Eigen::MatrixXd & C,
+    int & e,
+    int & e1,
+    int & e2,
+    int & f1,
+    int & f2);
+  /// \overload
   IGL_INLINE bool collapse_edge(
     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,
@@ -128,13 +160,7 @@ namespace igl
     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.
+  /// \overload
   IGL_INLINE bool collapse_edge(
     const decimate_cost_and_placement_callback & cost_and_placement,
     const decimate_pre_collapse_callback       & pre_collapse,
@@ -147,12 +173,7 @@ namespace igl
     Eigen::MatrixXi & EI,
     igl::min_heap< std::tuple<double,int,int> > & Q,
     Eigen::VectorXi & EQ,
-    Eigen::MatrixXd & C,
-    int & e,
-    int & e1,
-    int & e2,
-    int & f1,
-    int & f2);
+    Eigen::MatrixXd & C);
 }
 
 #ifndef IGL_STATIC_LIBRARY

+ 14 - 16
include/igl/collapse_small_triangles.h

@@ -10,22 +10,20 @@
 #include <Eigen/Dense>
 namespace igl
 {
-  // Given a triangle mesh (V,F) compute a new mesh (VV,FF) which contains the
-  // original faces and vertices of (V,F) except any small triangles have been
-  // removed via collapse.
-  //
-  // We are *not* following the rules in "Mesh Optimization" [Hoppe et al]
-  // Section 4.2. But for our purposes we don't care about this criteria.
-  //
-  // Inputs:
-  //   V  #V by 3 list of vertex positions
-  //   F  #F by 3 list of triangle indices into V
-  //   eps  epsilon for smallest allowed area treated as fraction of squared bounding box
-  //     diagonal
-  // Outputs:
-  //   FF  #FF by 3 list of triangle indices into V
-  //
-  //
+  /// Given a triangle mesh (V,F) compute a new mesh (VV,FF) which contains the
+  /// original faces and vertices of (V,F) except any small triangles have been
+  /// removed via collapse.
+  ///
+  /// We are *not* following the rules in "Mesh Optimization" [Hoppe et al]
+  /// Section 4.2. But for our purposes we don't care about this criteria.
+  ///
+  /// @param[in]  V  #V by 3 list of vertex positions
+  /// @param[in] F  #F by 3 list of triangle indices into V
+  /// @param[in] eps  epsilon for smallest allowed area treated as fraction of squared bounding box
+  ///     diagonal
+  /// @param[out] FF  #FF by 3 list of triangle indices into V
+  ///
+  ///
   void collapse_small_triangles(
     const Eigen::MatrixXd & V,
     const Eigen::MatrixXi & F,

+ 62 - 29
include/igl/colon.h

@@ -11,47 +11,80 @@
 #include <Eigen/Dense>
 namespace igl
 {
-  // Note:
-  // This should be potentially replaced with eigen's LinSpaced() function
-  //
-  // If step = 1, it's about 5 times faster to use:
-  //     X = Eigen::VectorXi::LinSpaced(n,0,n-1);
-  // than 
-  //     X = igl::colon<int>(0,n-1);
-  //
 
-  // Colon operator like matlab's colon operator. Enumerats values between low
-  // and hi with step step.
-  // Templates:
-  //   L  should be a eigen matrix primitive type like int or double
-  //   S  should be a eigen matrix primitive type like int or double
-  //   H  should be a eigen matrix primitive type like int or double
-  //   T  should be a eigen matrix primitive type like int or double
-  // Inputs:
-  //   low  starting value if step is valid then this is *always* the first
-  //     element of I
-  //   step  step difference between sequential elements returned in I,
-  //     remember this will be cast to template T at compile time. If low<hi
-  //     then step must be positive. If low>hi then step must be negative.
-  //     Otherwise I will be set to empty.
-  //   hi  ending value, if (hi-low)%step is zero then this will be the last
-  //     element in I. If step is positive there will be no elements greater
-  //     than hi, vice versa if hi<low
-  // Output:
-  //   I  list of values from low to hi with step size step
+  /// Colon operator like matlab's colon operator. Enumerates values between low
+  /// and hi with step step.
+  ///
+  /// @tparam L  should be a eigen matrix primitive type like int or double
+  /// @tparam S  should be a eigen matrix primitive type like int or double
+  /// @tparam H  should be a eigen matrix primitive type like int or double
+  /// @tparam T  should be a eigen matrix primitive type like int or double
+  /// @param[in] low  starting value if step is valid then this is *always* the first
+  ///     element of I
+  /// @param[in] step  step difference between sequential elements returned in I,
+  ///     remember this will be cast to template T at compile time. If low<hi
+  ///     then step must be positive. If low>hi then step must be negative.
+  ///     Otherwise I will be set to empty.
+  /// @param[in] hi  ending value, if (hi-low)%step is zero then this will be the last
+  ///     element in I. If step is positive there will be no elements greater
+  ///     than hi, vice versa if hi<low
+  /// @param[out] I  list of values from low to hi with step size step
+  ///
+  /// \note
+  /// This should be potentially replaced with eigen's LinSpaced() function
+  ///
+  /// If step = 1, it's about 5 times faster to use:
+  ///     X = Eigen::VectorXi::LinSpaced(n,0,n-1);
+  /// than 
+  ///     X = igl::colon<int>(0,n-1);
+  ///
   template <typename L,typename S,typename H,typename T>
   IGL_INLINE void colon(
     const L low, 
     const S step, 
     const H hi, 
     Eigen::Matrix<T,Eigen::Dynamic,1> & I);
-  // Same as above but step == (T)1
+  /// Colon operator like matlab's colon operator. Enumerates values between low
+  /// and hi with unit step.
+  ///
+  /// @tparam L  should be a eigen matrix primitive type like int or double
+  /// @tparam H  should be a eigen matrix primitive type like int or double
+  /// @tparam T  should be a eigen matrix primitive type like int or double
+  /// @param[in] low  starting value if step is valid then this is *always* the first
+  ///     element of I
+  /// @param[in] step  step difference between sequential elements returned in I,
+  ///     remember this will be cast to template T at compile time. If low<hi
+  ///     then step must be positive. If low>hi then step must be negative.
+  ///     Otherwise I will be set to empty.
+  /// @param[in] hi  ending value, if (hi-low)%step is zero then this will be the last
+  ///     element in I. If step is positive there will be no elements greater
+  ///     than hi, vice versa if hi<low
+  /// @param[out] I  list of values from low to hi with step size step
   template <typename L,typename H,typename T>
   IGL_INLINE void colon(
     const L low, 
     const H hi, 
     Eigen::Matrix<T,Eigen::Dynamic,1> & I);
-  // Return output rather than set in reference
+  /// @private
+  ///
+  /// Hiding this from doxygen because it's messing up the indentation.
+  ///
+  /// Colon operator like matlab's colon operator. Enumerates values between low
+  /// and hi with unit step.
+  ///
+  /// @tparam T  should be a eigen matrix primitive type like int or double
+  /// @tparam L  should be a eigen matrix primitive type like int or double
+  /// @tparam H  should be a eigen matrix primitive type like int or double
+  /// @param[in] low  starting value if step is valid then this is *always* the first
+  ///     element of I
+  /// @param[in] step  step difference between sequential elements returned in I,
+  ///     remember this will be cast to template T at compile time. If low<hi
+  ///     then step must be positive. If low>hi then step must be negative.
+  ///     Otherwise I will be set to empty.
+  /// @param[in] hi  ending value, if (hi-low)%step is zero then this will be the last
+  ///     element in I. If step is positive there will be no elements greater
+  ///     than hi, vice versa if hi<low
+  /// @return list of values from low to hi with step size step
   template <typename T,typename L,typename H>
   IGL_INLINE Eigen::Matrix<T,Eigen::Dynamic,1> colon(
     const L low, 

+ 38 - 23
include/igl/colormap.h

@@ -14,6 +14,7 @@
 
 namespace igl {
 
+  // Common colormap types. 
   enum ColorMapType
   {
     COLOR_MAP_TYPE_INFERNO = 0,
@@ -25,42 +26,56 @@ namespace igl {
     COLOR_MAP_TYPE_TURBO = 6,
     NUM_COLOR_MAP_TYPES = 7
   };
-  // Comput [r,g,b] values of the selected colormap for
-  // a given factor f between 0 and 1
-  //
-  // Inputs:
-  //   c  colormap enum
-  //   f  factor determining color value as if 0 was min and 1 was max
-  // Outputs:
-  //   rgb  red, green, blue value
+  /// Compute [r,g,b] values of the selected colormap for
+  /// a given factor f between 0 and 1
+  ///
+  /// @param[in] c  colormap enum
+  /// @param[in] f  factor determining color value as if 0 was min and 1 was max
+  /// @param[out] rgb  red, green, blue value
   template <typename T>
   IGL_INLINE void colormap(const ColorMapType cm, const T f, T * rgb);
-  // Outputs:
-  //   r  red value
-  //   g  green value
-  //   b  blue value
+  /// Compute [r,g,b] values of the selected colormap for
+  /// a given factor f between 0 and 1
+  ///
+  /// @param[in] c  colormap enum
+  /// @param[in] f  factor determining color value as if 0 was min and 1 was max
+  /// @param[out] r  red value
+  /// @param[out] g  green value
+  /// @param[out] b  blue value
   template <typename T>
   IGL_INLINE void colormap(const ColorMapType cm, const T f, T & r, T & g, T & b);
-  // Inputs:
-  //    palette  256 by 3 array of color values
+  /// Compute [r,g,b] values of the colormap palette for
+  /// a given factor f between 0 and 1
+  ///
+  /// @param[in] palette  256 by 3 array of color values
+  /// @param[in] x_in  factor determining color value as if 0 was min and 1 was max
+  /// @param[out] r  red value
+  /// @param[out] g  green value
+  /// @param[out] b  blue value
   template <typename T>
   IGL_INLINE void colormap(
     const double palette[256][3], const T x_in, T & r, T & g, T & b);
-  // Inputs:
-  //   cm selected colormap palette to interpolate from
-  //   Z  #Z list of factors
-  //   normalize  whether to normalize Z to be tightly between [0,1]
-  // Outputs:
-  //   C  #C by 3 list of rgb colors
+  /// Compute [r,g,b] values of the colormap palette for
+  /// a given factors between 0 and 1
+  ///
+  ///  @param[in] cm selected colormap palette to interpolate from
+  ///  @param[in] Z  #Z list of factors
+  ///  @param[in] normalize  whether to normalize Z to be tightly between [0,1]
+  ///  @param[out] C  #C by 3 list of rgb colors
   template <typename DerivedZ, typename DerivedC>
   IGL_INLINE void colormap(
     const ColorMapType cm,
     const Eigen::MatrixBase<DerivedZ> & Z,
     const bool normalize,
     Eigen::PlainObjectBase<DerivedC> & C);
-  // Inputs:
-  //   min_z  value at "0"
-  //   max_z  value at "1"
+  /// Compute [r,g,b] values of the colormap palette for
+  /// a given factors between `min_Z` and `max_Z`
+  ///
+  ///  @param[in] cm selected colormap palette to interpolate from
+  ///  @param[in] Z  #Z list of factors
+  ///  @param[in] min_z  value at "0"
+  ///  @param[in] max_z  value at "1"
+  ///  @param[out] C  #C by 3 list of rgb colors
   template <typename DerivedZ, typename DerivedC>
   IGL_INLINE void colormap(
     const ColorMapType cm,

+ 5 - 7
include/igl/column_to_quats.h

@@ -14,13 +14,11 @@
 #include <vector>
 namespace igl
 {
-  // "Columnize" a list of quaternions (q1x,q1y,q1z,q1w,q2x,q2y,q2z,q2w,...)
-  //
-  // Inputs:
-  //   Q  n*4-long list of coefficients
-  // Outputs:
-  //   vQ  n-long list of quaternions
-  // Returns false if n%4!=0
+  /// de-"Columnize" a list of quaternions (q1x,q1y,q1z,q1w,q2x,q2y,q2z,q2w,...)
+  ///
+  /// @param[in] Q  n*4-long list of coefficients
+  /// @param[out] vQ  n-long list of quaternions
+  /// @return false if n%4!=0
   IGL_INLINE bool column_to_quats(
     const Eigen::VectorXd & Q,
     std::vector<

+ 13 - 16
include/igl/columnize.h

@@ -12,22 +12,19 @@
 #include <Eigen/Core>
 namespace igl
 {
-  // "Columnize" a stack of block matrices. If A = [A1,A2,A3,...,Ak] with each A*
-  // an m by n block then this produces the column vector whose entries are 
-  // B(j*m*k+i*k+b) = A(i,b*n+j);
-  // or if A = [A1;A2;...;Ak] then
-  // B(j*m*k+i*k+b) = A(i+b*m,j);
-  //
-  // Templates:
-  //   T  should be a eigen matrix primitive type like int or double
-  // Inputs:
-  //   A  m*k by n (dim: 1) or m by n*k (dim: 2) eigen Matrix of type T values
-  //   k  number of blocks
-  //   dim  dimension in which blocks are stacked
-  // Output
-  //   B  m*n*k eigen vector of type T values,
-  //
-  // See also: transpose_blocks
+  /// "Columnize" a stack of block matrices. If A = [A1,A2,A3,...,Ak] with each A*
+  /// an m by n block then this produces the column vector whose entries are 
+  /// B(j*m*k+i*k+b) = A(i,b*n+j);
+  /// or if A = [A1;A2;...;Ak] then
+  /// B(j*m*k+i*k+b) = A(i+b*m,j);
+  ///
+  /// @tparam T  should be a eigen matrix primitive type like int or double
+  /// @param[in] A  m*k by n (dim: 1) or m by n*k (dim: 2) eigen Matrix of type T values
+  /// @param[in] k  number of blocks
+  /// @param[in] dim  dimension in which blocks are stacked
+  /// @param[out] B  m*n*k eigen vector of type T values,
+  ///
+  /// \see transpose_blocks
   template <typename DerivedA, typename DerivedB>
   IGL_INLINE void columnize(
     const Eigen::PlainObjectBase<DerivedA> & A,

+ 10 - 14
include/igl/comb_cross_field.h

@@ -12,20 +12,16 @@
 #include <Eigen/Core>
 namespace igl
 {
-  // Computes principal matchings of the vectors of a cross field across face edges,
-  // and generates a combed cross field defined on the mesh faces
-  
-  // Inputs:
-  //   V          #V by 3 eigen Matrix of mesh vertex 3D positions
-  //   F          #F by 4 eigen Matrix of face (quad) indices
-  //   PD1in      #F by 3 eigen Matrix of the first per face cross field vector
-  //   PD2in      #F by 3 eigen Matrix of the second per face cross field vector
-  // Output:
-  //   PD1out      #F by 3 eigen Matrix of the first combed cross field vector
-  //   PD2out      #F by 3 eigen Matrix of the second combed cross field vector
-  //
-  
-  
+  /// Computes principal matchings of the vectors of a cross field across face edges,
+  /// and generates a combed cross field defined on the mesh faces
+  ///
+  /// @param[in]  V          #V by 3 eigen Matrix of mesh vertex 3D positions
+  /// @param[in]  F          #F by 4 eigen Matrix of face (quad) indices
+  /// @param[in]  PD1in      #F by 3 eigen Matrix of the first per face cross field vector
+  /// @param[in]  PD2in      #F by 3 eigen Matrix of the second per face cross field vector
+  /// @param[out] PD1out      #F by 3 eigen Matrix of the first combed cross field vector
+  /// @param[out] PD2out      #F by 3 eigen Matrix of the second combed cross field vector
+  ///
   template <typename DerivedV, typename DerivedF>
   IGL_INLINE void comb_cross_field(const Eigen::MatrixBase<DerivedV> &V,
                                    const Eigen::MatrixBase<DerivedF> &F,

+ 14 - 18
include/igl/comb_frame_field.h

@@ -12,24 +12,20 @@
 #include <Eigen/Core>
 namespace igl
 {
-  // Computes principal matchings of the vectors of a frame field across face edges,
-  // and generates a combed frame field defined on the mesh faces. This makes use of a
-  // combed cross field generated by combing the field created by the bisectors of the
-  // frame field.
-
-  // Inputs:
-  //   V            #V by 3 eigen Matrix of mesh vertex 3D positions
-  //   F            #F by 4 eigen Matrix of face (quad) indices
-  //   PD1          #F by 3 eigen Matrix of the first per face cross field vector
-  //   PD2          #F by 3 eigen Matrix of the second per face cross field vector
-  //   BIS1_combed  #F by 3 eigen Matrix of the first combed bisector field vector
-  //   BIS2_combed  #F by 3 eigen Matrix of the second combed bisector field vector
-  // Output:
-  //   PD1_combed  #F by 3 eigen Matrix of the first combed cross field vector
-  //   PD2_combed  #F by 3 eigen Matrix of the second combed cross field vector
-  //
-
-
+  /// Computes principal matchings of the vectors of a frame field across face edges,
+  /// and generates a combed frame field defined on the mesh faces. This makes use of a
+  /// combed cross field generated by combing the field created by the bisectors of the
+  /// frame field.
+  ///
+  /// @param[in] V            #V by 3 eigen Matrix of mesh vertex 3D positions
+  /// @param[in] F            #F by 4 eigen Matrix of face (quad) indices
+  /// @param[in] PD1          #F by 3 eigen Matrix of the first per face cross field vector
+  /// @param[in] PD2          #F by 3 eigen Matrix of the second per face cross field vector
+  /// @param[in] BIS1_combed  #F by 3 eigen Matrix of the first combed bisector field vector
+  /// @param[in] BIS2_combed  #F by 3 eigen Matrix of the second combed bisector field vector
+  /// @param[out] PD1_combed  #F by 3 eigen Matrix of the first combed cross field vector
+  /// @param[out] PD2_combed  #F by 3 eigen Matrix of the second combed cross field vector
+  ///
   template <typename DerivedV, typename DerivedF, typename DerivedP>
   IGL_INLINE void comb_frame_field(const Eigen::MatrixBase<DerivedV> &V,
                                         const Eigen::MatrixBase<DerivedF> &F,

+ 7 - 11
include/igl/comb_line_field.h

@@ -12,17 +12,13 @@
 #include <Eigen/Core>
 namespace igl
 {
-  // Computes principal matchings of the vectors of a cross field across face edges,
-  // and generates a combed cross field defined on the mesh faces
-
-  // Inputs:
-  //   V          #V by 3 eigen Matrix of mesh vertex 3D positions
-  //   F          #F by 4 eigen Matrix of face (quad) indices
-  //   PD1in      #F by 3 eigen Matrix of the first per face cross field vector
-  // Output:
-  //   PD1out      #F by 3 eigen Matrix of the first combed cross field vector
-
-
+  /// Computes principal matchings of the vectors of a cross field across face edges,
+  /// and generates a combed cross field defined on the mesh faces
+  ///
+  /// @param[in] V          #V by 3 eigen Matrix of mesh vertex 3D positions
+  /// @param[in] F          #F by 4 eigen Matrix of face (quad) indices
+  /// @param[in] PD1in      #F by 3 eigen Matrix of the first per face cross field vector
+  /// @param[out] PD1out      #F by 3 eigen Matrix of the first combed cross field vector
   template <typename DerivedV, typename DerivedF>
   IGL_INLINE void comb_line_field(const Eigen::MatrixBase<DerivedV> &V,
                                   const Eigen::MatrixBase<DerivedF> &F,

+ 20 - 19
include/igl/combine.h

@@ -14,25 +14,25 @@
 
 namespace igl
 {
-  // Concatenate k meshes into a single >=k connected component mesh with a
-  // single vertex list and face list. Similar to Maya's Combine operation. 
-  //
-  // Inputs:
-  //   VV  k-long list of lists of mesh vertex positions
-  //   FF  k-long list of lists of mesh face indices so that FF[i] indexes
-  //     VV[i]
-  // Outputs:
-  //   V   VV[0].rows()+...+VV[k-1].rows() by VV[0].cols() list of mesh
-  //     vertex positions
-  //   F   FF[0].rows()+...+FF[k-1].rows() by FF[0].cols() list of mesh faces
-  //     indices into V
-  //   Vsizes  k list so that Vsizes(i) is the #vertices in the ith input
-  //   Fsizes  k list so that Fsizes(i) is the #faces in the ith input
-  // Example:
-  //   // Suppose you have mesh A (VA,FA) and mesh B (VB,FB)
-  //   igl::combine<Eigen::MatrixXd,Eigen::MatrixXi>({VA,VB},{FA,FB},V,F);
-  //
-  //
+  /// Concatenate k meshes into a single >=k connected component mesh with a
+  /// single vertex list and face list. Similar to Maya's Combine operation. 
+  ///
+  /// @param[in] VV  k-long list of lists of mesh vertex positions
+  /// @param[in] FF  k-long list of lists of mesh face indices so that FF[i] indexes
+  ///     VV[i]
+  /// @param[out] V   VV[0].rows()+...+VV[k-1].rows() by VV[0].cols() list of mesh
+  ///     vertex positions
+  /// @param[out] F   FF[0].rows()+...+FF[k-1].rows() by FF[0].cols() list of mesh faces
+  ///     indices into V
+  /// @param[out] Vsizes  k list so that Vsizes(i) is the #vertices in the ith input
+  /// @param[out] Fsizes  k list so that Fsizes(i) is the #faces in the ith input
+  ///
+  /// #### Example
+  /// \code{cpp}
+  ///   // Suppose you have mesh A (VA,FA) and mesh B (VB,FB)
+  ///   igl::combine<Eigen::MatrixXd,Eigen::MatrixXi>({VA,VB},{FA,FB},V,F);
+  /// \endcode
+  ///
   template <
     typename DerivedVV, 
     typename DerivedFF, 
@@ -47,6 +47,7 @@ namespace igl
     Eigen::PlainObjectBase<DerivedF> & F,
     Eigen::PlainObjectBase<DerivedVsizes> & Vsizes,
     Eigen::PlainObjectBase<DerivedFsizes> & Fsizes);
+  /// \overload
   template <
     typename DerivedVV, 
     typename DerivedFF, 

+ 26 - 28
include/igl/compute_frame_field_bisectors.h

@@ -12,38 +12,36 @@
 #include <Eigen/Core>
 namespace igl
 {
-  // Compute bisectors of a frame field defined on mesh faces
-  // Inputs:
-  //   V     #V by 3 eigen Matrix of mesh vertex 3D positions
-  //   F     #F by 3 eigen Matrix of face (triangle) indices
-  //   B1    #F by 3 eigen Matrix of face (triangle) base vector 1
-  //   B2    #F by 3 eigen Matrix of face (triangle) base vector 2
-  //   PD1   #F by 3 eigen Matrix of the first per face frame field vector
-  //   PD2   #F by 3 eigen Matrix of the second per face frame field vector
-  // Output:
-  //   BIS1  #F by 3 eigen Matrix of the first per face frame field bisector
-  //   BIS2  #F by 3 eigen Matrix of the second per face frame field bisector
-  //
+  /// Compute bisectors of a frame field defined on mesh faces
+  ///
+  /// @param[in] V     #V by 3 eigen Matrix of mesh vertex 3D positions
+  /// @param[in] F     #F by 3 eigen Matrix of face (triangle) indices
+  /// @param[in] B1    #F by 3 eigen Matrix of face (triangle) base vector 1
+  /// @param[in] B2    #F by 3 eigen Matrix of face (triangle) base vector 2
+  /// @param[in] PD1   #F by 3 eigen Matrix of the first per face frame field vector
+  /// @param[in] PD2   #F by 3 eigen Matrix of the second per face frame field vector
+  /// @param[out] BIS1  #F by 3 eigen Matrix of the first per face frame field bisector
+  /// @param[out] BIS2  #F by 3 eigen Matrix of the second per face frame field bisector
+  ///
   template <typename DerivedV, typename DerivedF>
   IGL_INLINE void compute_frame_field_bisectors(
-                                                const Eigen::MatrixBase<DerivedV>& V,
-                                                const Eigen::MatrixBase<DerivedF>& F,
-                                                const Eigen::MatrixBase<DerivedV>& B1,
-                                                const Eigen::MatrixBase<DerivedV>& B2,
-                                                const Eigen::MatrixBase<DerivedV>& PD1,
-                                                const Eigen::MatrixBase<DerivedV>& PD2,
-                                                Eigen::PlainObjectBase<DerivedV>& BIS1,
-                                                Eigen::PlainObjectBase<DerivedV>& BIS2);
-
-  // Wrapper without given basis vectors.
+    const Eigen::MatrixBase<DerivedV>& V,
+    const Eigen::MatrixBase<DerivedF>& F,
+    const Eigen::MatrixBase<DerivedV>& B1,
+    const Eigen::MatrixBase<DerivedV>& B2,
+    const Eigen::MatrixBase<DerivedV>& PD1,
+    const Eigen::MatrixBase<DerivedV>& PD2,
+    Eigen::PlainObjectBase<DerivedV>& BIS1,
+    Eigen::PlainObjectBase<DerivedV>& BIS2);
+  /// \overload
   template <typename DerivedV, typename DerivedF>
   IGL_INLINE void compute_frame_field_bisectors(
-                                                const Eigen::MatrixBase<DerivedV>& V,
-                                                const Eigen::MatrixBase<DerivedF>& F,
-                                                const Eigen::MatrixBase<DerivedV>& PD1,
-                                                const Eigen::MatrixBase<DerivedV>& PD2,
-                                                Eigen::PlainObjectBase<DerivedV>& BIS1,
-                                                Eigen::PlainObjectBase<DerivedV>& BIS2);
+    const Eigen::MatrixBase<DerivedV>& V,
+    const Eigen::MatrixBase<DerivedF>& F,
+    const Eigen::MatrixBase<DerivedV>& PD1,
+    const Eigen::MatrixBase<DerivedV>& PD2,
+    Eigen::PlainObjectBase<DerivedV>& BIS1,
+    Eigen::PlainObjectBase<DerivedV>& BIS2);
 }
 
 #ifndef IGL_STATIC_LIBRARY

+ 23 - 19
include/igl/connect_boundary_to_infinity.h

@@ -11,34 +11,38 @@
 #include <Eigen/Core>
 namespace igl
 {
-  // Connect all boundary edges to a fictitious point at infinity.
-  //
-  // Inputs:
-  //   F  #F by 3 list of face indices into some V
-  // Outputs:
-  //   FO  #F+#O by 3 list of face indices into [V;inf inf inf], original F are
-  //     guaranteed to come first. If (V,F) was a manifold mesh, now it is
-  //     closed with a possibly non-manifold vertex at infinity (but it will be
-  //     edge-manifold).
+  /// Connect all boundary edges to a fictitious point at infinity.
+  ///
+  /// @param[in] F  #F by 3 list of face indices into some V
+  /// @param[out] FO  #F+#O by 3 list of face indices into [V;inf inf inf], original F are
+  ///     guaranteed to come first. If (V,F) was a manifold mesh, now it is
+  ///     closed with a possibly non-manifold vertex at infinity (but it will be
+  ///     edge-manifold).
   template <typename DerivedF, typename DerivedFO>
   IGL_INLINE void connect_boundary_to_infinity(
     const Eigen::MatrixBase<DerivedF> & F,
     Eigen::PlainObjectBase<DerivedFO> & FO);
-  // Inputs:
-  //   inf_index  index of point at infinity (usually V.rows() or F.maxCoeff())
+  /// Connect all boundary edges to a fictitious point at infinity.
+  ///
+  /// @param[in] F  #F by 3 list of face indices into some V
+  /// @param[in] inf_index  index of point at infinity (usually V.rows() or F.maxCoeff())
+  /// @param[out] FO  #F+#O by 3 list of face indices into [V;inf inf inf], original F are
+  ///     guaranteed to come first. If (V,F) was a manifold mesh, now it is
+  ///     closed with a possibly non-manifold vertex at infinity (but it will be
+  ///     edge-manifold).
   template <typename DerivedF, typename DerivedFO>
   IGL_INLINE void connect_boundary_to_infinity(
     const Eigen::MatrixBase<DerivedF> & F,
     const typename DerivedF::Scalar inf_index,
     Eigen::PlainObjectBase<DerivedFO> & FO);
-  // Inputs:
-  //   V  #V by 3 list of vertex positions
-  //   F  #F by 3 list of face indices into some V
-  // Outputs:
-  //   VO  #V+1 by 3 list of vertex positions, original V are guaranteed to
-  //     come first. Last point is inf, inf, inf
-  //   FO  #F+#O by 3 list of face indices into VO
-  // 
+  /// Connect all boundary edges to a fictitious point at infinity.
+  ///
+  /// @param[in] V  #V by 3 list of vertex positions
+  /// @param[in] F  #F by 3 list of face indices into some V
+  /// @param[out] VO  #V+1 by 3 list of vertex positions, original V are guaranteed to
+  ///     come first. Last point is inf, inf, inf
+  /// @param[out] FO  #F+#O by 3 list of face indices into VO
+  /// 
   template <
     typename DerivedV, 
     typename DerivedF, 

+ 8 - 10
include/igl/connected_components.h

@@ -12,16 +12,14 @@
 #include <Eigen/Sparse>
 namespace igl
 {
-  // Determine the connected components of a graph described by the input
-  // adjacency matrix (similar to MATLAB's graphconncomp or gptoolbox's
-  // conncomp, but A is transposed for unsymmetric graphs).
-  //
-  // Inputs:
-  //    A  #A by #A adjacency matrix (treated as describing an directed graph)
-  // Outputs:
-  //    C  #A list of component indices into [0,#K-1]
-  //    K  #K list of sizes of each component
-  // Returns number of connected components
+  /// Determine the connected components of a graph described by the input
+  /// adjacency matrix (similar to MATLAB's graphconncomp or gptoolbox's
+  /// conncomp, but A is transposed for unsymmetric graphs).
+  ///
+  /// @param[in]  A  #A by #A adjacency matrix (treated as describing an directed graph)
+  /// @param[out] C  #A list of component indices into [0,#K-1]
+  /// @param[out] K  #K list of sizes of each component
+  /// @return number of connected components
   template < typename Atype, typename DerivedC, typename DerivedK>
   IGL_INLINE int connected_components(
     const Eigen::SparseMatrix<Atype> & A,

+ 14 - 6
include/igl/copyleft/cgal/BinaryWindingNumberOperations.h

@@ -26,6 +26,7 @@ namespace igl
   {
     namespace cgal
     {
+      /// Binary winding number operations
       template <igl::MeshBooleanType Op>
       class BinaryWindingNumberOperations {
         public:
@@ -36,7 +37,7 @@ namespace igl
             }
       };
 
-      // A ∪ B ∪ ... ∪ Z
+      /// A ∪ B ∪ ... ∪ Z
       template <>
       class BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_UNION> {
         public:
@@ -52,7 +53,7 @@ namespace igl
           }
       };
 
-      // A ∩ B ∩ ... ∩ Z
+      /// A ∩ B ∩ ... ∩ Z
       template <>
       class BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_INTERSECT> {
         public:
@@ -68,7 +69,7 @@ namespace igl
           }
       };
 
-      // A \ B \ ... \ Z = A \ (B ∪ ... ∪ Z)
+      /// A \ B \ ... \ Z = A \ (B ∪ ... ∪ Z)
       template <>
       class BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_MINUS> {
         public:
@@ -89,7 +90,7 @@ namespace igl
           }
       };
 
-      // A ∆ B ∆ ... ∆ Z  (equivalent to set inside odd number of objects)
+      /// A ∆ B ∆ ... ∆ Z  (equivalent to set inside odd number of objects)
       template <>
       class BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_XOR> {
         public:
@@ -107,6 +108,7 @@ namespace igl
           }
       };
 
+      /// Resolve all intersections without removing non-coplanar faces
       template <>
       class BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_RESOLVE> {
         public:
@@ -123,11 +125,15 @@ namespace igl
       typedef BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_XOR> BinaryXor;
       typedef BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_RESOLVE> BinaryResolve;
 
+      /// Types of Keep policies
       enum KeeperType {
+        /// Keep only inside
         KEEP_INSIDE,
+        /// Keep everything
         KEEP_ALL
       };
 
+      /// Filter winding numbers according to keep policy
       template<KeeperType T>
       class WindingNumberFilter {
         public:
@@ -138,6 +144,7 @@ namespace igl
             }
       };
 
+      /// Keep inside policy
       template<>
       class WindingNumberFilter<KEEP_INSIDE> {
         public:
@@ -149,6 +156,7 @@ namespace igl
           }
       };
 
+      /// Keep all policy
       template<>
       class WindingNumberFilter<KEEP_ALL> {
         public:
@@ -158,8 +166,8 @@ namespace igl
             }
       };
 
-      typedef WindingNumberFilter<KEEP_INSIDE> KeepInside;
-      typedef WindingNumberFilter<KEEP_ALL> KeepAll;
+      using KeepInside = WindingNumberFilter<KEEP_INSIDE>;
+      using KeepAll = WindingNumberFilter<KEEP_ALL>;
     }
   }
 }

+ 19 - 20
include/igl/copyleft/cgal/CSGTree.h

@@ -20,10 +20,9 @@ namespace igl
   {
     namespace cgal
     {
-      // Class for defining and computing a constructive solid geometry result
-      // out of a tree of boolean operations on "solid" triangle meshes.
-      //
-      //template <typename DerivedF>
+      /// Class for defining and computing a constructive solid geometry result
+      /// out of a tree of boolean operations on "solid" triangle meshes.
+      ///
       class CSGTree
       {
         public:
@@ -33,12 +32,14 @@ namespace igl
           typedef Eigen::Matrix<ExactScalar,Eigen::Dynamic,3> MatrixX3E;
           typedef Eigen::VectorXi VectorJ;
         private:
-          // Resulting mesh
+          /// Resulting mesh vertex positions
           MatrixX3E m_V;
+          /// Resulting mesh face indices into V
           POBF m_F;
+          /// Birth index of each face in resulting mesh. Birth index is the index
           VectorJ m_J;
-          // Number of birth faces in A + those in B. I.e. sum of original "leaf"
-          // faces involved in result.
+          /// Number of birth faces in A + those in B. I.e. sum of original "leaf"
+          /// faces involved in result.
           size_t m_number_of_birth_faces;
         public:
           CSGTree()
@@ -82,12 +83,11 @@ namespace igl
           {
             swap(*this,other);
           }
-          // Construct and compute a boolean operation on existing CSGTree nodes.
-          //
-          // Inputs:
-          //   A  Solid result of previous CSG operation (or identity, see below)
-          //   B  Solid result of previous CSG operation (or identity, see below)
-          //   type  type of mesh boolean to compute 
+          /// Construct and compute a boolean operation on existing CSGTree nodes.
+          ///
+          /// @param[in] A  Solid result of previous CSG operation (or identity, see below)
+          /// @param[in] B  Solid result of previous CSG operation (or identity, see below)
+          /// @param[in] type  type of mesh boolean to compute 
           CSGTree(
             const CSGTree & A,
             const CSGTree & B,
@@ -111,7 +111,7 @@ namespace igl
             m_number_of_birth_faces = 
               A.number_of_birth_faces() + B.number_of_birth_faces();
           }
-          // Overload using string for type
+          /// \overload
           CSGTree(
             const CSGTree & A,
             const CSGTree & B,
@@ -120,12 +120,11 @@ namespace igl
           {
             // do nothing (all done in constructor).
           }
-          // "Leaf" node with identity operation on assumed "solid" mesh (V,F)
-          //
-          // Inputs:
-          //   V  #V by 3 list of mesh vertices (in any precision, will be
-          //     converted to exact)
-          //   F  #F by 3 list of mesh face indices into V
+          /// "Leaf" node with identity operation on assumed "solid" mesh (V,F)
+          ///
+          /// @param[in] V  #V by 3 list of mesh vertices (in any precision, will be
+          ///     converted to exact)
+          /// @param[in] F  #F by 3 list of mesh face indices into V
           template <typename DerivedV>
           CSGTree(const Eigen::PlainObjectBase<DerivedV> & V, const POBF & F)//:
           // Possible Eigen bug:

+ 9 - 10
include/igl/copyleft/cgal/RemeshSelfIntersectionsParam.h

@@ -14,21 +14,20 @@ namespace igl
   {
     namespace cgal
     {
-      // Optional Parameters
-      //   DetectOnly  Only compute IF, leave VV and FF alone
-      //
-      // detect_only  avoid constructing intersections results when possible
-      // first_only  return after detecting the first intersection (if
-      //   first_only==true, then detect_only should also be true)
-      // stitch_all  whether to stitch all resulting constructed elements into a
-      //   (non-manifold) mesh 
-      // slow_and_more_precise_rounding  whether to use slow and more precise
-      //   rounding (see assign_scalar)
+      /// Parameters for SelfIntersectMesh, remesh_self_intersections and
+      /// remesh_intersections, and intersect_other
+      ///
       struct RemeshSelfIntersectionsParam
       {
+        /// avoid constructing intersections results when possible
         bool detect_only;
+        /// return after detecting the first intersection (if first_only==true,
+        /// then detect_only should also be true)
         bool first_only;
+        /// whether to stitch all resulting constructed elements into a
+        /// (non-manifold) mesh 
         bool stitch_all;
+        /// whether to use slow and more precise rounding (see assign_scalar)
         bool slow_and_more_precise_rounding;
         inline RemeshSelfIntersectionsParam(
           bool _detect_only=false, 

+ 81 - 55
include/igl/copyleft/cgal/SelfIntersectMesh.h

@@ -34,11 +34,12 @@ namespace igl
   {
     namespace cgal
     {
-      // Kernel is a CGAL kernel like:
-      //     CGAL::Exact_predicates_inexact_constructions_kernel
-      // or
-      //     CGAL::Exact_predicates_exact_constructions_kernel
-
+      /// Class for computing the self-intersections of a mesh
+      ///
+      /// @tparam Kernel is a CGAL kernel like:
+      ///     CGAL::Exact_predicates_inexact_constructions_kernel
+      /// or
+      ///     CGAL::Exact_predicates_exact_constructions_kernel
       template <
         typename Kernel,
         typename DerivedV,
@@ -109,10 +110,20 @@ namespace igl
         public:
           RemeshSelfIntersectionsParam params;
         public:
-          // Constructs (VV,FF) a new mesh with self-intersections of (V,F)
-          // subdivided
-          //
-          // See also: remesh_self_intersections.h
+          /// Constructs (VV,FF) a new mesh with self-intersections of (V,F)
+          /// subdivided
+          ///
+          /// @param[in] V  #V by 3 list of vertex positions
+          /// @param[in] F  #F by 3 list of triangle indices into V
+          /// @param[in] params  parameters
+          /// @param[out] VV  #VV by 3 list of vertex positions
+          /// @param[out] FF  #FF by 3 list of triangle indices into VV
+          /// @param[out] IF  #IF by 2 list of edge indices into VV
+          /// @param[out] J  #F list of indices into FF of birth parents
+          /// @param[out] IM  #VV list of indices into V of birth parents
+          ///
+          ///
+          /// \see remesh_self_intersections.h
           inline SelfIntersectMesh(
               const Eigen::MatrixBase<DerivedV> & V,
               const Eigen::MatrixBase<DerivedF> & F,
@@ -123,47 +134,43 @@ namespace igl
               Eigen::PlainObjectBase<DerivedJ> & J,
               Eigen::PlainObjectBase<DerivedIM> & IM);
         private:
-          // Helper function to mark a face as offensive
-          //
-          // Inputs:
-          //   f  index of face in F
+          /// Helper function to mark a face as offensive
+          ///
+          /// @param[in] f  index of face in F
           inline void mark_offensive(const Index f);
-          // Helper function to count intersections between faces
-          //
-          // Input:
-          //   fa  index of face A in F
-          //   fb  index of face B in F
+          /// Helper function to count intersections between faces
+          ///
+          /// @param[in] fa  index of face A in F
+          /// @param[in] fb  index of face B in F
           inline void count_intersection( const Index fa, const Index fb);
-          // Helper function for box_intersect. Intersect two triangles A and B,
-          // append the intersection object (point,segment,triangle) to a running
-          // list for A and B
-          //
-          // Inputs:
-          //   A  triangle in 3D
-          //   B  triangle in 3D
-          //   fa  index of A in F (and key into offending)
-          //   fb  index of B in F (and key into offending)
-          // Returns true only if A intersects B
-          //
+          /// Helper function for box_intersect. Intersect two triangles A and B,
+          /// append the intersection object (point,segment,triangle) to a running
+          /// list for A and B
+          ///
+          /// @param[in] A  triangle in 3D
+          /// @param[in] B  triangle in 3D
+          /// @param[in] fa  index of A in F (and key into offending)
+          /// @param[in] fb  index of B in F (and key into offending)
+          /// @return true only if A intersects B
+          ///
           inline bool intersect(
               const Triangle_3 & A,
               const Triangle_3 & B,
               const Index fa,
               const Index fb);
-          // Helper function for box_intersect. In the case where A and B have
-          // already been identified to share a vertex, then we only want to
-          // add possible segment intersections. Assumes truly duplicate
-          // triangles are not given as input
-          //
-          // Inputs:
-          //   A  triangle in 3D
-          //   B  triangle in 3D
-          //   fa  index of A in F (and key into offending)
-          //   fb  index of B in F (and key into offending)
-          //   va  index of shared vertex in A (and key into offending)
-          //   vb  index of shared vertex in B (and key into offending)
-          //   Returns true if intersection (besides shared point)
-          //
+          /// Helper function for box_intersect. In the case where A and B have
+          /// already been identified to share a vertex, then we only want to
+          /// add possible segment intersections. Assumes truly duplicate
+          /// triangles are not given as input
+          ///
+          /// @param[in] A  triangle in 3D
+          /// @param[in] B  triangle in 3D
+          /// @param[in] fa  index of A in F (and key into offending)
+          /// @param[in] fb  index of B in F (and key into offending)
+          /// @param[in] va  index of shared vertex in A (and key into offending)
+          /// @param[in] vb  index of shared vertex in B (and key into offending)
+          /// @return true if intersection (besides shared point)
+          ///
           inline bool single_shared_vertex(
               const Triangle_3 & A,
               const Triangle_3 & B,
@@ -171,17 +178,31 @@ namespace igl
               const Index fb,
               const Index va,
               const Index vb);
-          // Helper handling one direction
+          //// Helper handling one direction
+          ///
+          /// @param[in] A  triangle in 3D
+          /// @param[in] B  triangle in 3D
+          /// @param[in] fa  index of A in F (and key into offending)
+          /// @param[in] fb  index of B in F (and key into offending)
+          /// @param[in] va  index of shared vertex in A (and key into offending)
+          /// @return true if intersection (besides shared point)
           inline bool single_shared_vertex(
               const Triangle_3 & A,
               const Triangle_3 & B,
               const Index fa,
               const Index fb,
               const Index va);
-          // Helper function for box_intersect. In the case where A and B have
-          // already been identified to share two vertices, then we only want
-          // to add a possible coplanar (Triangle) intersection. Assumes truly
-          // degenerate facets are not givin as input.
+          /// Helper function for box_intersect. In the case where A and B have
+          /// already been identified to share two vertices, then we only want
+          /// to add a possible coplanar (Triangle) intersection. Assumes truly
+          /// degenerate facets are not givin as input.
+          ///
+          /// @param[in] A  triangle in 3D
+          /// @param[in] B  triangle in 3D
+          /// @param[in] fa  index of A in F (and key into offending)
+          /// @param[in] fb  index of B in F (and key into offending)
+          /// @param[in] shared  list of pairs of indices of shared vertices
+          /// @return true if intersection (besides shared point)
           inline bool double_shared_vertex(
               const Triangle_3 & A,
               const Triangle_3 & B,
@@ -190,18 +211,23 @@ namespace igl
               const std::vector<std::pair<Index,Index> > shared);
 
         public:
-          // Callback function called during box self intersections test. Means
-          // boxes a and b intersect. This method then checks if the triangles
-          // in each box intersect and if so, then processes the intersections
-          //
-          // Inputs:
-          //   a  box containing a triangle
-          //   b  box containing a triangle
+          /// Callback function called during box self intersections test. Means
+          /// boxes a and b intersect. This method then checks if the triangles
+          /// in each box intersect and if so, then processes the intersections
+          ///
+          /// @param[in] a  box containing a triangle
+          /// @param[in] b  box containing a triangle
           inline void box_intersect(const Box& a, const Box& b);
+          /// Process all of the intersecting boxes
           inline void process_intersecting_boxes();
         public:
           // Getters:
           //const IndexList& get_lIF() const{ return lIF;}
+          /// Static function that captures a SelfIntersectMesh instance to pass
+          /// to cgal.
+          /// @param[in] SIM  pointer to SelfIntersectMesh instance
+          /// @param[in] a  box containing a triangle
+          /// @param[in] b  box containing a triangle
           static inline void box_intersect_static(
             SelfIntersectMesh * SIM,
             const Box &a,

+ 9 - 5
include/igl/copyleft/cgal/assign.h

@@ -17,20 +17,24 @@ namespace igl
   {
     namespace cgal
     {
-      // Inputs:
-      //   C  matrix of scalars
-      //   slow_and_more_precise  see assign_scalar
-      // Outputs:
-      //   D  matrix same size as C
+      /// Vector version of assign_scalar
+      ///
+      /// @param[in] C  matrix of scalars
+      /// @param[in] slow_and_more_precise  see assign_scalar
+      /// @param[out] D  matrix same size as C
+      ///
+      /// \see assign_scalar
       template <typename DerivedC, typename DerivedD>
       IGL_INLINE void assign(
         const Eigen::MatrixBase<DerivedC> & C,
         const bool slow_and_more_precise,
         Eigen::PlainObjectBase<DerivedD> & D);
+      /// \overload
       template <typename DerivedC, typename DerivedD>
       IGL_INLINE void assign(
         const Eigen::MatrixBase<DerivedC> & C,
         Eigen::PlainObjectBase<DerivedD> & D);
+      /// \overload
       template <typename ReturnScalar, typename DerivedC>
       IGL_INLINE 
       Eigen::Matrix<

+ 36 - 28
include/igl/copyleft/cgal/assign_scalar.h

@@ -21,76 +21,84 @@ namespace igl
   {
     namespace cgal
     {
-      // Conduct the casting copy:
-      //   lhs = rhs
-      // using `slow_and_more_precise` rounding if more desired.
-      //
-      // Inputs:
-      //   rhs  right-hand side scalar
-      //   slow_and_more_precise  when appropriate use more elaborate rounding
-      //     guaranteed to find a closest lhs value in an absolute value sense.
-      //     Think of `slow_and_more_precise=true` as "round to closest number"
-      //     and `slow_and_more_precise=false` as "round down/up". CGAL's number
-      //     types are bit mysterious about how exactly rounding is conducted.
-      //     For example, the rationals created during remesh_intersections on
-      //     floating point input appear to be tightly rounded up or down so the
-      //     difference with the `slow_and_more_precise=true` will be exactly
-      //     zero 50% of the time and "one floating point unit" (at whatever
-      //     scale) the other 50% of the time.
-      // Outputs:
-      //   lhs  left-hand side scalar
+      /// Conduct the casting copy:
+      ///   lhs = rhs
+      /// using `slow_and_more_precise` rounding if more desired.
+      ///
+      /// @tparam RHS right-hand side scalar type
+      /// @tparam LHS left-hand side scalar type
+      /// @param[in] rhs  right-hand side scalar
+      /// @param[in] slow_and_more_precise  when appropriate use more elaborate rounding
+      ///     guaranteed to find a closest lhs value in an absolute value sense.
+      ///     Think of `slow_and_more_precise=true` as "round to closest number"
+      ///     and `slow_and_more_precise=false` as "round down/up". CGAL's number
+      ///     types are bit mysterious about how exactly rounding is conducted.
+      ///     For example, the rationals created during remesh_intersections on
+      ///     floating point input appear to be tightly rounded up or down so the
+      ///     difference with the `slow_and_more_precise=true` will be exactly
+      ///     zero 50% of the time and "one floating point unit" (at whatever
+      ///     scale) the other 50% of the time.
+      /// @param[out] lhs  left-hand side scalar
       template <typename RHS, typename LHS>
       IGL_INLINE void assign_scalar(
         const RHS & rhs,
         const bool & slow_and_more_precise,
         LHS & lhs);
-      // For legacy reasons, all of these overload uses
-      // `slow_and_more_precise=true`. This is subject to change if we determine
-      // it is sufficiently overkill. In that case, we'd create a new
-      // non-overloaded function.
-      //
-      // Inputs:
-      //   cgal  cgal scalar
-      // Outputs:
-      //   d  output scalar
+      /// \overload
+      /// \brief For legacy reasons, all of these overload uses
+      /// `slow_and_more_precise=true`. This is subject to change if we determine
+      /// it is sufficiently overkill. In that case, we'd create a new
+      /// non-overloaded function.
       IGL_INLINE void assign_scalar(
         const CGAL::Epeck::FT & cgal,
         CGAL::Epeck::FT & d);
+      /// \overload
       IGL_INLINE void assign_scalar(
         const CGAL::Epeck::FT & cgal,
         double & d);
+      /// \overload
       IGL_INLINE void assign_scalar(
+      /// \overload
         const CGAL::Epeck::FT & cgal,
         float& d);
       IGL_INLINE void assign_scalar(
+      /// \overload
         const double & c,
         double & d);
+      /// \overload
       IGL_INLINE void assign_scalar(
         const float& c,
         float & d);
+      /// \overload
       IGL_INLINE void assign_scalar(
         const float& c,
         double& d);
+      /// \overload
       IGL_INLINE void assign_scalar(
         const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
         CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & d);
+      /// \overload
       IGL_INLINE void assign_scalar(
         const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
         double & d);
+      /// \overload
       IGL_INLINE void assign_scalar(
         const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
         float& d);
 #ifndef WIN32
+      /// \overload
       IGL_INLINE void assign_scalar(
         const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
         CGAL::Simple_cartesian<mpq_class>::FT & d);
+      /// \overload
       IGL_INLINE void assign_scalar(
         const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
         double & d);
+      /// \overload
       IGL_INLINE void assign_scalar(
         const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
         float& d);
-#endif // WIN32
+#endif
     }
   }
 }

+ 10 - 14
include/igl/copyleft/cgal/cell_adjacency.h

@@ -20,20 +20,16 @@ namespace igl
   {
     namespace cgal
     {
-      // Inputs:
-      //   per_patch_cells  #P by 2 list of cell labels on each side of each
-      //                    patch.  Cell labels are assumed to be continuous
-      //                    from 0 to #C.
-      //   num_cells        number of cells.
-      //
-      // Outputs:
-      //   adjacency_list  #C array of list of adjcent cell information.  If
-      //                   cell i and cell j are adjacent via patch x, where i
-      //                   is on the positive side of x, and j is on the
-      //                   negative side.  Then,
-      //                   adjacency_list[i] will contain the entry {j, false, x}
-      //                   and
-      //                   adjacency_list[j] will contain the entry {i, true, x}
+      /// Determine adjacency of cells
+      ///
+      /// @param[in] per_patch_cells  #P by 2 list of cell labels on each side
+      ///   of each patch.  Cell labels are assumed to be continuous from 0 to #C.
+      /// @param[in] num_cells        number of cells.
+      /// @param[out] adjacency_list  #C array of list of adjcent cell
+      ///   information.  If cell i and cell j are adjacent via patch x, where i
+      ///   is on the positive side of x, and j is on the negative side.  Then,
+      ///   adjacency_list[i] will contain the entry {j, false, x} and
+      ///   adjacency_list[j] will contain the entry {i, true, x}
       template < typename DerivedC >
       IGL_INLINE void cell_adjacency(
           const Eigen::PlainObjectBase<DerivedC>& per_patch_cells,

+ 23 - 20
include/igl/copyleft/cgal/closest_facet.h

@@ -25,26 +25,26 @@ namespace igl
   {
     namespace cgal
     {
-      // Determine the closest facet for each of the input points.
-      //
-      // Inputs:
-      //   V  #V by 3 array of vertices.
-      //   F  #F by 3 array of faces.
-      //   I  #I list of triangle indices to consider.
-      //   P  #P by 3 array of query points.
-      //  EMAP  #F*3 list of indices into uE.
-      //  uEC  #uE+1 list of cumsums of directed edges sharing each unique edge
-      //  uEE  #E list of indices into E (see `igl::unique_edge_map`)
-      //   VF  #V list of lists of incident faces (adjacency list)
-      //   VFi  #V list of lists of index of incidence within incident faces
-      //     listed in VF
-      //   tree  AABB containing triangles of (V,F(I,:))
-      //   triangles  #I list of cgal triangles
-      //   in_I  #F list of whether in submesh
-      // Outputs:
-      //   R  #P list of closest facet indices.
-      //   S  #P list of bools indicating on which side of the closest facet
-      //      each query point lies.
+      /// Determine the closest facet for each of the input points.
+      ///
+      /// @param[in] V  #V by 3 array of vertices.
+      /// @param[in] F  #F by 3 array of faces.
+      /// @param[in] I  #I list of triangle indices to consider.
+      /// @param[in] P  #P by 3 array of query points.
+      /// @param[in] EMAP  #F*3 list of indices into uE.
+      /// @param[in] uEC  #uE+1 list of cumsums of directed edges sharing each unique edge
+      /// @param[in] uEE  #E list of indices into E (see `igl::unique_edge_map`)
+      /// @param[in] VF  #V list of lists of incident faces (adjacency list)
+      /// @param[in] VFi  #V list of lists of index of incidence within incident faces listed in VF
+      /// @param[in] tree  AABB containing triangles of (V,F(I,:))
+      /// @param[in] triangles  #I list of cgal triangles
+      /// @param[in] in_I  #F list of whether in submesh
+      /// @param[out] R  #P list of closest facet indices.
+      /// @param[out] S  #P list of bools indicating on which side of the closest facet
+      ///      each query point lies.
+      ///
+      /// \note The use of `size_t` here is a bad idea. These should just be int
+      /// to avoid nonsense with windows.
       template<
         typename DerivedV,
         typename DerivedF,
@@ -76,6 +76,7 @@ namespace igl
           const std::vector<bool> & in_I,
           Eigen::PlainObjectBase<DerivedR>& R,
           Eigen::PlainObjectBase<DerivedS>& S);
+      /// \overload
       template<
         typename DerivedV,
         typename DerivedF,
@@ -96,6 +97,7 @@ namespace igl
         const Eigen::PlainObjectBase<DeriveduEE>& uEE,
               Eigen::PlainObjectBase<DerivedR>& R,
               Eigen::PlainObjectBase<DerivedS>& S);
+      /// \overload
       template<
         typename DerivedV,
         typename DerivedF,
@@ -114,6 +116,7 @@ namespace igl
         const Eigen::PlainObjectBase<DeriveduEE>& uEE,
         Eigen::PlainObjectBase<DerivedR>& R,
         Eigen::PlainObjectBase<DerivedS>& S);
+      /// \overload
       template<
         typename DerivedV,
         typename DerivedF,

+ 10 - 12
include/igl/copyleft/cgal/complex_to_mesh.h

@@ -18,18 +18,16 @@ namespace igl
   {
     namespace cgal
     {
-      // Templates:
-      //   Tr  CGAL triangulation type, e.g.
-      //     CGAL::Surface_mesh_default_triangulation_3
-      // Inputs
-      //   c2t3  2-complex (surface) living in a 3d triangulation (e.g. result of
-      //     CGAL::make_surface_mesh)
-      // Outputs:
-      //   V  #V by 3 list of vertex positions
-      //   F  #F by 3 list of triangle indices
-      // Returns true iff conversion was successful, failure can ok if CGAL code
-      // can't figure out ordering.
-      //
+      /// Convert a CGAL::Complex_2_in_triangulation_3 to a mesh (V,F)
+      ///
+      /// @tparam Tr  CGAL triangulation type, e.g. CGAL::Surface_mesh_default_triangulation_3
+      /// @param[in] c2t3  2-complex (surface) living in a 3d triangulation
+      ///   (e.g. result of CGAL::make_surface_mesh)
+      /// @param[out] V  #V by 3 list of vertex positions
+      /// @param[out] F  #F by 3 list of triangle indices
+      /// @return true iff conversion was successful, failure can ok if CGAL code
+      /// can't figure out ordering.
+      ///
       template <typename Tr, typename DerivedV, typename DerivedF>
       IGL_INLINE bool complex_to_mesh(
         const CGAL::Complex_2_in_triangulation_3<Tr> & c2t3,

+ 31 - 50
include/igl/copyleft/cgal/component_inside_component.h

@@ -15,56 +15,37 @@
 namespace igl {
   namespace copyleft
   {
-    namespace cgal {
-
-        // Determine if connected facet component (V1, F1, I1) is inside of
-        // connected facet component (V2, F2, I2).
-        //
-        // Precondition:
-        // Both components must represent closed, self-intersection free,
-        // non-degenerated surfaces that are the boundary of 3D volumes. In
-        // addition, (V1, F1, I1) must not intersect with (V2, F2, I2).
-        //
-        // Inputs:
-        //   V1  #V1 by 3 list of vertex position of mesh 1
-        //   F1  #F1 by 3 list of triangles indices into V1
-        //   I1  #I1 list of indices into F1, indicate the facets of component
-        //   V2  #V2 by 3 list of vertex position of mesh 2
-        //   F2  #F2 by 3 list of triangles indices into V2
-        //   I2  #I2 list of indices into F2, indicate the facets of component
-        //
-        // Outputs:
-        //   return true iff (V1, F1, I1) is entirely inside of (V2, F2, I2).
-        template<typename DerivedV, typename DerivedF, typename DerivedI>
-            IGL_INLINE bool component_inside_component(
-                    const Eigen::PlainObjectBase<DerivedV>& V1,
-                    const Eigen::PlainObjectBase<DerivedF>& F1,
-                    const Eigen::PlainObjectBase<DerivedI>& I1,
-                    const Eigen::PlainObjectBase<DerivedV>& V2,
-                    const Eigen::PlainObjectBase<DerivedF>& F2,
-                    const Eigen::PlainObjectBase<DerivedI>& I2);
-
-        // Determine if mesh (V1, F1) is inside of mesh (V2, F2).
-        //
-        // Precondition:
-        // Both meshes must be closed, self-intersection free, non-degenerated
-        // surfaces that are the boundary of 3D volumes.  They should not
-        // intersect each other.
-        //
-        // Inputs:
-        //   V1  #V1 by 3 list of vertex position of mesh 1
-        //   F1  #F1 by 3 list of triangles indices into V1
-        //   V2  #V2 by 3 list of vertex position of mesh 2
-        //   F2  #F2 by 3 list of triangles indices into V2
-        //
-        // Outputs:
-        //   return true iff (V1, F1) is entirely inside of (V2, F2).
-        template<typename DerivedV, typename DerivedF>
-            IGL_INLINE bool component_inside_component(
-                    const Eigen::PlainObjectBase<DerivedV>& V1,
-                    const Eigen::PlainObjectBase<DerivedF>& F1,
-                    const Eigen::PlainObjectBase<DerivedV>& V2,
-                    const Eigen::PlainObjectBase<DerivedF>& F2);
+    namespace cgal 
+    {
+      /// Determine if connected facet component (V1, F1, I1) is inside of
+      /// connected facet component (V2, F2, I2).
+      ///
+      /// \pre Both components must represent closed, self-intersection free,
+      /// non-degenerated surfaces that are the boundary of 3D volumes. In
+      /// addition, (V1, F1, I1) must not intersect with (V2, F2, I2).
+      ///
+      /// @param[in] V1  #V1 by 3 list of vertex position of mesh 1
+      /// @param[in] F1  #F1 by 3 list of triangles indices into V1
+      /// @param[in] I1  #I1 list of indices into F1, indicate the facets of component
+      /// @param[in] V2  #V2 by 3 list of vertex position of mesh 2
+      /// @param[in] F2  #F2 by 3 list of triangles indices into V2
+      /// @param[in] I2  #I2 list of indices into F2, indicate the facets of component
+      /// @return true iff (V1, F1, I1) is entirely inside of (V2, F2, I2).
+      template<typename DerivedV, typename DerivedF, typename DerivedI>
+          IGL_INLINE bool component_inside_component(
+                  const Eigen::PlainObjectBase<DerivedV>& V1,
+                  const Eigen::PlainObjectBase<DerivedF>& F1,
+                  const Eigen::PlainObjectBase<DerivedI>& I1,
+                  const Eigen::PlainObjectBase<DerivedV>& V2,
+                  const Eigen::PlainObjectBase<DerivedF>& F2,
+                  const Eigen::PlainObjectBase<DerivedI>& I2);
+      /// \overload
+      template<typename DerivedV, typename DerivedF>
+          IGL_INLINE bool component_inside_component(
+                  const Eigen::PlainObjectBase<DerivedV>& V1,
+                  const Eigen::PlainObjectBase<DerivedF>& F1,
+                  const Eigen::PlainObjectBase<DerivedV>& V2,
+                  const Eigen::PlainObjectBase<DerivedF>& F2);
     }
   }
 }

+ 6 - 15
include/igl/copyleft/cgal/convex_hull.h

@@ -16,13 +16,11 @@ namespace igl
   {
     namespace cgal
     {
-      // Given a set of points (V), compute the convex hull as a triangle mesh (W,G)
-      // 
-      // Inputs:
-      //   V  #V by 3 list of input points
-      // Outputs:
-      //   W  #W by 3 list of convex hull points
-      //   G  #G by 3 list of triangle indices into W
+      /// Given a set of points (V), compute the convex hull as a triangle mesh (W,G)
+      /// 
+      /// @param[in] V  #V by 3 list of input points
+      /// @param[out] W  #W by 3 list of convex hull points
+      /// @param[out] G  #G by 3 list of triangle indices into W
       template <
         typename DerivedV,
         typename DerivedW,
@@ -31,14 +29,7 @@ namespace igl
         const Eigen::MatrixBase<DerivedV> & V,
         Eigen::PlainObjectBase<DerivedW> & W,
         Eigen::PlainObjectBase<DerivedG> & G);
-      // Given a set of points (V), compute the convex hull as a triangle mesh (F)
-      // over input vertex set (V)
-      // 
-      // Inputs:
-      //   V  #V by 3 list of input points
-      // Outputs:
-      //   F  #F by 3 list of triangle indices into V
-      //
+      /// \overload
       template <
         typename DerivedV,
         typename DerivedF>

+ 4 - 5
include/igl/copyleft/cgal/coplanar.h

@@ -8,11 +8,10 @@ namespace igl
   {
     namespace cgal
     {
-      // Test whether all points are on same plane.
-      //
-      // Inputs:
-      //   V  #V by 3 list of 3D vertex positions
-      // Returns true if all points lie on the same plane
+      /// Test whether all points are on same plane.
+      ///
+      /// @param[in] V  #V by 3 list of 3D vertex positions
+      /// @return true if all points lie on the same plane
       template <typename DerivedV>
       IGL_INLINE bool coplanar(
         const Eigen::MatrixBase<DerivedV> & V);

+ 5 - 9
include/igl/copyleft/cgal/delaunay_triangulation.h

@@ -18,15 +18,11 @@ namespace igl
   {
     namespace cgal
     {
-
-      // Given a set of points in 2D, return a Delaunay triangulation of these
-      // points.
-      //
-      // Inputs:
-      //   V  #V by 2 list of vertex positions
-      //
-      // Outputs:
-      //   F  #F by 3 of faces in Delaunay triangulation.
+      /// Given a set of points in 2D, return a Delaunay triangulation of these
+      /// points.
+      ///
+      /// @param[in] V  #V by 2 list of vertex positions
+      /// @param[out] F  #F by 3 of faces in Delaunay triangulation.
       template<
         typename DerivedV,
         typename DerivedF

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно